From a7474d5bccb21c5c4cd0f2295ec02bb32daf0679 Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 30 Aug 2017 20:56:34 -0600 Subject: [PATCH 01/18] Hopefully fixing camera issue --- Source/SwiftyCamViewController.swift | 45 +++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 66dc57c..638657a 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -242,6 +242,10 @@ open class SwiftyCamViewController: UIViewController { /// Last changed orientation fileprivate var deviceOrientation : UIDeviceOrientation? + + /// Boolean to store when View Controller is notified session is running + + fileprivate var sessionRunning = false /// Disable view autorotation for forced portrait recorindg @@ -291,7 +295,7 @@ open class SwiftyCamViewController: UIViewController { self.configureSession() } } - + // MARK: ViewDidLayoutSubviews /// ViewDidLayoutSubviews() Implementation @@ -340,14 +344,25 @@ open class SwiftyCamViewController: UIViewController { } } } + + // MARK: ViewWillAppear + + /// ViewWillAppear(_ animated:) Implementation + + open override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + NotificationCenter.default.addObserver(self, selector: #selector(captureSessionDidStartRunning), name: .AVCaptureSessionDidStartRunning, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(captureSessionDidStopRunning), name: .AVCaptureSessionDidStopRunning, object: nil) + } + + + // MARK: ViewDidAppear /// ViewDidAppear(_ animated:) Implementation - - override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + // Subscribe to device rotation notifications if shouldUseDeviceOrientation { @@ -392,6 +407,9 @@ open class SwiftyCamViewController: UIViewController { override open func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) + + NotificationCenter.default.removeObserver(self) + sessionRunning = false // If session is running, stop the session if self.isSessionRunning == true { @@ -423,6 +441,7 @@ open class SwiftyCamViewController: UIViewController { guard let device = videoDevice else { return } + if device.hasFlash == true && flashEnabled == true /* TODO: Add Support for Retina Flash and add front flash */ { changeFlashSettings(device: device, mode: .on) @@ -831,6 +850,12 @@ open class SwiftyCamViewController: UIViewController { } fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) { + + guard sessionRunning == true else { + print("[SwiftyCam]: Cannot take photo while session isn't running") + return + } + if let videoConnection = photoFileOutput?.connection(withMediaType: AVMediaTypeVideo) { photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in @@ -994,6 +1019,18 @@ open class SwiftyCamViewController: UIViewController { } } + + /// Called when Notification Center registers session starts running + + @objc private func captureSessionDidStartRunning() { + sessionRunning = true + } + + /// Called when Notification Center registers session stops running + + @objc private func captureSessionDidStopRunning() { + sessionRunning = false + } } extension SwiftyCamViewController : SwiftyCamButtonDelegate { From 2f4784ae3954f8cd8b6a1a58834062c9296a6b19 Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 30 Aug 2017 20:59:38 -0600 Subject: [PATCH 02/18] Added check for start recording video --- Source/SwiftyCamViewController.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 638657a..2a86dff 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -482,6 +482,11 @@ open class SwiftyCamViewController: UIViewController { */ public func startVideoRecording() { + + guard sessionRunning == true else { + print("[SwiftyCam]: Cannot start video recoding. Capture session is not running") + return + } guard let movieFileOutput = self.movieFileOutput else { return } @@ -852,7 +857,7 @@ open class SwiftyCamViewController: UIViewController { fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) { guard sessionRunning == true else { - print("[SwiftyCam]: Cannot take photo while session isn't running") + print("[SwiftyCam]: Cannot take photo. Capture session is not running") return } From 85d9bc917c03e762c78f4dffc505e1f142489fba Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 30 Aug 2017 21:17:54 -0600 Subject: [PATCH 03/18] Added delegate for failed configuration --- .../DemoSwiftyCam/ViewController.swift | 10 ++++++++++ Source/SwiftyCamViewController.swift | 17 +++++++---------- Source/SwiftyCamViewControllerDelegate.swift | 13 +++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 8d3e90f..17c6a5c 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -87,12 +87,22 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { }) }) } + + func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) { + let message = NSLocalizedString("Unable to capture media", comment: "Alert message when something goes wrong during capture session configuration") + let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) + present(alertController, animated: true, completion: nil) + } func swiftyCam(_ swiftyCam: SwiftyCamViewController, didChangeZoomLevel zoom: CGFloat) { + print("Zoom level did change. Level: \(zoom)") print(zoom) } func swiftyCam(_ swiftyCam: SwiftyCamViewController, didSwitchCameras camera: SwiftyCamViewController.CameraSelection) { + print("Camera did change to \(camera.rawValue)") + print(camera) } diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 2a86dff..332e0c4 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -27,13 +27,13 @@ open class SwiftyCamViewController: UIViewController { /// Enumeration for Camera Selection - public enum CameraSelection { + public enum CameraSelection: String { /// Camera on the back of the device - case rear + case rear = "rear" /// Camera on the front of the device - case front + case front = "front" } /// Enumeration for video quality of the capture session. Corresponds to a AVCaptureSessionPreset @@ -271,7 +271,7 @@ open class SwiftyCamViewController: UIViewController { // Test authorization status for Camera and Micophone - switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo){ + switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) { case .authorized: // already authorized @@ -390,12 +390,9 @@ open class SwiftyCamViewController: UIViewController { self.promptToAppSettings() case .configurationFailed: // Unknown Error - DispatchQueue.main.async(execute: { [unowned self] in - let message = NSLocalizedString("Unable to capture media", comment: "Alert message when something goes wrong during capture session configuration") - let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) - self.present(alertController, animated: true, completion: nil) - }) + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCamDidFailToConfigure(self) + } } } } diff --git a/Source/SwiftyCamViewControllerDelegate.swift b/Source/SwiftyCamViewControllerDelegate.swift index 8102f06..764b2c7 100644 --- a/Source/SwiftyCamViewControllerDelegate.swift +++ b/Source/SwiftyCamViewControllerDelegate.swift @@ -15,6 +15,7 @@ import UIKit +import AVFoundation // MARK: Public Protocol Declaration @@ -95,6 +96,14 @@ public protocol SwiftyCamViewControllerDelegate: class { */ func swiftyCam(_ swiftyCam: SwiftyCamViewController, didChangeZoomLevel zoom: CGFloat) + + /** + SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController fails to confiture the session. + + - Parameter swiftyCam: Current SwiftyCamViewController + */ + + func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) } public extension SwiftyCamViewControllerDelegate { @@ -135,6 +144,10 @@ public extension SwiftyCamViewControllerDelegate { func swiftyCam(_ swiftyCam: SwiftyCamViewController, didChangeZoomLevel zoom: CGFloat) { // Optional } + + func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) { + // Optional + } } From ad38933dca2db98ede52f65f17eaa9e4d6eba131 Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 30 Aug 2017 21:41:03 -0600 Subject: [PATCH 04/18] Added delegate to prompt to app settings --- .../DemoSwiftyCam.xcodeproj/project.pbxproj | 10 +++++----- DemoSwiftyCam/DemoSwiftyCam/ViewController.swift | 1 + Source/SwiftyCamViewController.swift | 11 +++++++++-- Source/SwiftyCamViewControllerDelegate.swift | 12 ++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index 6af0d11..b8b883f 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ }; 1675A9711E00A68300B80903 = { CreatedOnToolsVersion = 8.1; - DevelopmentTeam = DGV5BLXSF9; + DevelopmentTeam = G8E5P2X66G; ProvisioningStyle = Automatic; }; }; @@ -421,11 +421,11 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = DGV5BLXSF9; + DEVELOPMENT_TEAM = G8E5P2X66G; INFOPLIST_FILE = DemoSwiftyCam/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam; + PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -436,11 +436,11 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = DGV5BLXSF9; + DEVELOPMENT_TEAM = G8E5P2X66G; INFOPLIST_FILE = DemoSwiftyCam/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam; + PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 17c6a5c..6f9636c 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -25,6 +25,7 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() + shouldPrompToAppSettings = true cameraDelegate = self maximumVideoDuration = 10.0 shouldUseDeviceOrientation = true diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 332e0c4..5f51dab 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -158,6 +158,10 @@ open class SwiftyCamViewController: UIViewController { /// Setting to true will prompt user for access to microphone on View Controller launch. public var audioEnabled = true + /// Sets whether or not app should display prompt to app settings if audio/video permission is denied + /// If set to false, delegate function will be called to handle exception + public var shouldPrompToAppSettings = true + /// Public access to Pinch Gesture fileprivate(set) public var pinchGesture : UIPinchGestureRecognizer! @@ -386,8 +390,11 @@ open class SwiftyCamViewController: UIViewController { } case .notAuthorized: - // Prompt to App Settings - self.promptToAppSettings() + if self.shouldPrompToAppSettings == true { + self.promptToAppSettings() + } else { + self.cameraDelegate?.swiftyCamNotAuthorized(self) + } case .configurationFailed: // Unknown Error DispatchQueue.main.async { diff --git a/Source/SwiftyCamViewControllerDelegate.swift b/Source/SwiftyCamViewControllerDelegate.swift index 764b2c7..120312e 100644 --- a/Source/SwiftyCamViewControllerDelegate.swift +++ b/Source/SwiftyCamViewControllerDelegate.swift @@ -104,6 +104,14 @@ public protocol SwiftyCamViewControllerDelegate: class { */ func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) + + /** + SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController does not have access to camera or microphone. + + - Parameter swiftyCam: Current SwiftyCamViewController + */ + + func swiftyCamNotAuthorized(_ swiftyCam: SwiftyCamViewController) } public extension SwiftyCamViewControllerDelegate { @@ -148,6 +156,10 @@ public extension SwiftyCamViewControllerDelegate { func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) { // Optional } + + func swiftyCamNotAuthorized(_ swiftyCam: SwiftyCamViewController) { + // Optional + } } From d837d4d71eb9ec8ff32df8d183d357e256e3985a Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 6 Sep 2017 12:33:59 -0600 Subject: [PATCH 05/18] Added optional delegate methods for running session and added enabled property to SwiftyCamButton --- .../DemoSwiftyCam/ViewController.swift | 91 +++++++++++++------ Source/SwiftyCamButton.swift | 12 +++ Source/SwiftyCamViewController.swift | 8 +- Source/SwiftyCamViewControllerDelegate.swift | 26 ++++++ 4 files changed, 106 insertions(+), 31 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 6f9636c..69b087d 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -18,10 +18,9 @@ import UIKit class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { - @IBOutlet weak var captureButton: SwiftyRecordButton! - @IBOutlet weak var flipCameraButton: UIButton! - @IBOutlet weak var flashButton: UIButton! - + @IBOutlet weak var captureButton : SwiftyRecordButton! + @IBOutlet weak var flipCameraButton : UIButton! + @IBOutlet weak var flashButton : UIButton! override func viewDidLoad() { super.viewDidLoad() @@ -31,6 +30,9 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { shouldUseDeviceOrientation = true allowAutoRotate = true audioEnabled = true + + // disable capture button until session starts + captureButton.buttonEnabled = false } override var prefersStatusBarHidden: Bool { @@ -41,6 +43,17 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { super.viewDidAppear(animated) captureButton.delegate = self } + + func swiftyCamSessionDidStartRunning(_ swiftyCam: SwiftyCamViewController) { + print("Session did start running") + captureButton.buttonEnabled = true + } + + func swiftyCamSessionDidStopRunning(_ swiftyCam: SwiftyCamViewController) { + print("Session did stop running") + captureButton.buttonEnabled = false + } + func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage) { let newVC = PhotoViewController(image: photo) @@ -50,19 +63,13 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { func swiftyCam(_ swiftyCam: SwiftyCamViewController, didBeginRecordingVideo camera: SwiftyCamViewController.CameraSelection) { print("Did Begin Recording") captureButton.growButton() - UIView.animate(withDuration: 0.25, animations: { - self.flashButton.alpha = 0.0 - self.flipCameraButton.alpha = 0.0 - }) + hideButtons() } func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishRecordingVideo camera: SwiftyCamViewController.CameraSelection) { print("Did finish Recording") captureButton.shrinkButton() - UIView.animate(withDuration: 0.25, animations: { - self.flashButton.alpha = 1.0 - self.flipCameraButton.alpha = 1.0 - }) + showButtons() } func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishProcessVideoAt url: URL) { @@ -71,22 +78,8 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { } func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFocusAtPoint point: CGPoint) { - let focusView = UIImageView(image: #imageLiteral(resourceName: "focus")) - focusView.center = point - focusView.alpha = 0.0 - view.addSubview(focusView) - - UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: { - focusView.alpha = 1.0 - focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25) - }, completion: { (success) in - UIView.animate(withDuration: 0.15, delay: 0.5, options: .curveEaseInOut, animations: { - focusView.alpha = 0.0 - focusView.transform = CGAffineTransform(translationX: 0.6, y: 0.6) - }, completion: { (success) in - focusView.removeFromSuperview() - }) - }) + print("Did focus at point: \(point)") + focusAnimationAt(point) } func swiftyCamDidFailToConfigure(_ swiftyCam: SwiftyCamViewController) { @@ -103,7 +96,6 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { func swiftyCam(_ swiftyCam: SwiftyCamViewController, didSwitchCameras camera: SwiftyCamViewController.CameraSelection) { print("Camera did change to \(camera.rawValue)") - print(camera) } @@ -117,7 +109,48 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { @IBAction func toggleFlashTapped(_ sender: Any) { flashEnabled = !flashEnabled + toggleFlashAnimation() + } +} + + +// UI Animations +extension ViewController { + + fileprivate func hideButtons() { + UIView.animate(withDuration: 0.25) { + self.flashButton.alpha = 0.0 + self.flipCameraButton.alpha = 0.0 + } + } + + fileprivate func showButtons() { + UIView.animate(withDuration: 0.25) { + self.flashButton.alpha = 1.0 + self.flipCameraButton.alpha = 1.0 + } + } + + fileprivate func focusAnimationAt(_ point: CGPoint) { + let focusView = UIImageView(image: #imageLiteral(resourceName: "focus")) + focusView.center = point + focusView.alpha = 0.0 + view.addSubview(focusView) + UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: { + focusView.alpha = 1.0 + focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25) + }) { (success) in + UIView.animate(withDuration: 0.15, delay: 0.5, options: .curveEaseInOut, animations: { + focusView.alpha = 0.0 + focusView.transform = CGAffineTransform(translationX: 0.6, y: 0.6) + }) { (success) in + focusView.removeFromSuperview() + } + } + } + + fileprivate func toggleFlashAnimation() { if flashEnabled == true { flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControlState()) } else { diff --git a/Source/SwiftyCamButton.swift b/Source/SwiftyCamButton.swift index dce4162..a9e2448 100644 --- a/Source/SwiftyCamButton.swift +++ b/Source/SwiftyCamButton.swift @@ -54,6 +54,10 @@ open class SwiftyCamButton: UIButton { public weak var delegate: SwiftyCamButtonDelegate? + // Sets whether button is enabled + + public var buttonEnabled = true + /// Maximum duration variable fileprivate var timer : Timer? @@ -76,11 +80,19 @@ open class SwiftyCamButton: UIButton { /// UITapGestureRecognizer Function @objc fileprivate func Tap() { + guard buttonEnabled == true else { + return + } + delegate?.buttonWasTapped() } /// UILongPressGestureRecognizer Function @objc fileprivate func LongPress(_ sender:UILongPressGestureRecognizer!) { + guard buttonEnabled == true else { + return + } + switch sender.state { case .began: delegate?.buttonDidBeginLongPress() diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 5f51dab..1c1a8b5 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -359,8 +359,6 @@ open class SwiftyCamViewController: UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(captureSessionDidStopRunning), name: .AVCaptureSessionDidStopRunning, object: nil) } - - // MARK: ViewDidAppear /// ViewDidAppear(_ animated:) Implementation @@ -1033,12 +1031,18 @@ open class SwiftyCamViewController: UIViewController { @objc private func captureSessionDidStartRunning() { sessionRunning = true + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCamSessionDidStartRunning(self) + } } /// Called when Notification Center registers session stops running @objc private func captureSessionDidStopRunning() { sessionRunning = false + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCamSessionDidStopRunning(self) + } } } diff --git a/Source/SwiftyCamViewControllerDelegate.swift b/Source/SwiftyCamViewControllerDelegate.swift index 120312e..d2e8ee8 100644 --- a/Source/SwiftyCamViewControllerDelegate.swift +++ b/Source/SwiftyCamViewControllerDelegate.swift @@ -23,6 +23,24 @@ import AVFoundation public protocol SwiftyCamViewControllerDelegate: class { + /** + SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController session did start running. + Photos and video capture will be enabled. + + - Parameter swiftyCam: Current SwiftyCamViewController + */ + + func swiftyCamSessionDidStartRunning(_ swiftyCam: SwiftyCamViewController) + + /** + SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController session did stops running. + Photos and video capture will be disabled. + + - Parameter swiftyCam: Current SwiftyCamViewController + */ + + func swiftyCamSessionDidStopRunning(_ swiftyCam: SwiftyCamViewController) + /** SwiftyCamViewControllerDelegate function called when the takePhoto() function is called. @@ -116,6 +134,14 @@ public protocol SwiftyCamViewControllerDelegate: class { public extension SwiftyCamViewControllerDelegate { + func swiftyCamSessionDidStopRunning(_ swiftyCam: SwiftyCamViewController) { + // Optional + } + + func swiftyCamSessionDidStartRunning(_ swiftyCam: SwiftyCamViewController) { + // Optional + } + func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage) { // Optional } From 6b8d19620c05cb067b59b48084f5b85a6713299d Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 6 Sep 2017 13:24:22 -0600 Subject: [PATCH 06/18] Fixed issue with Bluetooth audio being forced onto device --- Source/SwiftyCamViewController.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 1c1a8b5..7d337de 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -1016,9 +1016,13 @@ open class SwiftyCamViewController: UIViewController { } do{ - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, - with: [.duckOthers, .defaultToSpeaker]) - + if #available(iOS 10.0, *) { + try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, + with: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP]) + } else { + try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, + with: [.mixWithOthers, .allowBluetooth]) + } session.automaticallyConfiguresApplicationAudioSession = false } catch { From c98cf8256deb1e2a5e691b2c5d7aa4b5709f2bdb Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 6 Sep 2017 13:43:57 -0600 Subject: [PATCH 07/18] Fixed issue with audio going over bluetooth --- .../DemoSwiftyCam.xcodeproj/project.pbxproj | 21 ++- .../xcschemes/SwiftyCam-iOS.xcscheme | 4 +- .../xcschemes/DemoSwiftyCam.xcscheme | 4 +- DemoSwiftyCam/DemoSwiftyCam/Info.plist | 2 + .../DemoSwiftyCam/PhotoViewController.swift | 2 +- .../DemoSwiftyCam/VideoViewController.swift | 16 ++- Source/PreviewView.swift | 6 +- Source/SwiftyCamViewController.swift | 124 +++++++++--------- 8 files changed, 106 insertions(+), 73 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index b8b883f..fed99d5 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -175,7 +175,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Cappsule; TargetAttributes = { 05D2A9B31E80BE9700B479E9 = { @@ -185,6 +185,7 @@ 1675A9711E00A68300B80903 = { CreatedOnToolsVersion = 8.1; DevelopmentTeam = G8E5P2X66G; + LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; }; @@ -333,7 +334,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -341,7 +344,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -383,7 +390,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -391,7 +400,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -427,7 +440,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -442,7 +456,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme index 95275f3..b6c9ea0 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme index 9a743aa..0e5254a 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme @@ -1,6 +1,6 @@ @@ -45,6 +46,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/DemoSwiftyCam/DemoSwiftyCam/Info.plist b/DemoSwiftyCam/DemoSwiftyCam/Info.plist index e3b8756..e3fcada 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/Info.plist +++ b/DemoSwiftyCam/DemoSwiftyCam/Info.plist @@ -2,6 +2,8 @@ + NSPhotoLibraryUsageDescription + To save videos CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift index 89dc74a..4333a1f 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift @@ -45,7 +45,7 @@ class PhotoViewController: UIViewController { view.addSubview(cancelButton) } - func cancel() { + @objc func cancel() { dismiss(animated: true, completion: nil) } } diff --git a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift index ce55aa9..0423a71 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift @@ -58,6 +58,20 @@ class VideoViewController: UIViewController { cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState()) cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) view.addSubview(cancelButton) + + + // Allow background audio to continue to play + do { + try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient) + } catch let error as NSError { + print(error) + } + + do { + try AVAudioSession.sharedInstance().setActive(true) + } catch let error as NSError { + print(error) + } } override func viewDidAppear(_ animated: Bool) { @@ -65,7 +79,7 @@ class VideoViewController: UIViewController { player?.play() } - func cancel() { + @objc func cancel() { dismiss(animated: true, completion: nil) } diff --git a/Source/PreviewView.swift b/Source/PreviewView.swift index f555d97..2b62c26 100644 --- a/Source/PreviewView.swift +++ b/Source/PreviewView.swift @@ -55,11 +55,11 @@ class PreviewView: UIView { let previewlayer = layer as! AVCaptureVideoPreviewLayer switch gravity { case .resize: - previewlayer.videoGravity = AVLayerVideoGravityResize + previewlayer.videoGravity = AVLayerVideoGravity.resize case .resizeAspect: - previewlayer.videoGravity = AVLayerVideoGravityResizeAspect + previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect case .resizeAspectFill: - previewlayer.videoGravity = AVLayerVideoGravityResizeAspectFill + previewlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill } return previewlayer } diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 7d337de..4a7e743 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -275,7 +275,7 @@ open class SwiftyCamViewController: UIViewController { // Test authorization status for Camera and Micophone - switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) { + switch AVCaptureDevice.authorizationStatus(for: AVMediaType.video) { case .authorized: // already authorized @@ -284,7 +284,7 @@ open class SwiftyCamViewController: UIViewController { // not yet determined sessionQueue.suspend() - AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { [unowned self] granted in + AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { [unowned self] granted in if !granted { self.setupResult = .notAuthorized } @@ -511,7 +511,7 @@ open class SwiftyCamViewController: UIViewController { } // Update the orientation on the movie file output video connection before starting recording. - let movieFileOutputConnection = self.movieFileOutput?.connection(withMediaType: AVMediaTypeVideo) + let movieFileOutputConnection = self.movieFileOutput?.connection(with: AVMediaType.video) //flip video output if front facing camera is selected @@ -524,7 +524,7 @@ open class SwiftyCamViewController: UIViewController { // Start recording to a temporary file. let outputFileName = UUID().uuidString let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!) - movieFileOutput.startRecording(toOutputFileURL: URL(fileURLWithPath: outputFilePath), recordingDelegate: self) + movieFileOutput.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: self) self.isVideoRecording = true DispatchQueue.main.async { self.cameraDelegate?.swiftyCam(self, didBeginRecordingVideo: self.currentCamera) @@ -599,7 +599,7 @@ open class SwiftyCamViewController: UIViewController { // remove and re-add inputs and outputs for input in self.session.inputs { - self.session.removeInput(input as! AVCaptureInput) + self.session.removeInput(input ) } self.addInputs() @@ -656,12 +656,12 @@ open class SwiftyCamViewController: UIViewController { fileprivate func configureVideoPreset() { if currentCamera == .front { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) + session.sessionPreset = AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: .high)) } else { - if session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality)) { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: videoQuality) + if session.canSetSessionPreset(AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: videoQuality))) { + session.sessionPreset = AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: videoQuality)) } else { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) + session.sessionPreset = AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: .high)) } } } @@ -671,9 +671,9 @@ open class SwiftyCamViewController: UIViewController { fileprivate func addVideoInput() { switch currentCamera { case .front: - videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .front) + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaType.video.rawValue, preferringPosition: .front) case .rear: - videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .back) + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaType.video.rawValue, preferringPosition: .back) } if let device = videoDevice { @@ -705,14 +705,14 @@ open class SwiftyCamViewController: UIViewController { } do { - let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) + let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice!) if session.canAddInput(videoDeviceInput) { session.addInput(videoDeviceInput) self.videoDeviceInput = videoDeviceInput } else { print("[SwiftyCam]: Could not add video device input to the session") - print(session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality))) + print(session.canSetSessionPreset(AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: videoQuality)))) setupResult = .configurationFailed session.commitConfiguration() return @@ -731,8 +731,8 @@ open class SwiftyCamViewController: UIViewController { return } do { - let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) - let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) + let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio) + let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!) if session.canAddInput(audioDeviceInput) { session.addInput(audioDeviceInput) @@ -753,7 +753,7 @@ open class SwiftyCamViewController: UIViewController { if self.session.canAddOutput(movieFileOutput) { self.session.addOutput(movieFileOutput) - if let connection = movieFileOutput.connection(withMediaType: AVMediaTypeVideo) { + if let connection = movieFileOutput.connection(with: AVMediaType.video) { if connection.isVideoStabilizationSupported { connection.preferredVideoStabilizationMode = .auto } @@ -807,7 +807,7 @@ open class SwiftyCamViewController: UIViewController { } fileprivate func getVideoOrientation() -> AVCaptureVideoOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection.videoOrientation } + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection!.videoOrientation } switch deviceOrientation { case .landscapeLeft: @@ -863,11 +863,11 @@ open class SwiftyCamViewController: UIViewController { return } - if let videoConnection = photoFileOutput?.connection(withMediaType: AVMediaTypeVideo) { + if let videoConnection = photoFileOutput?.connection(with: AVMediaType.video) { photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in if (sampleBuffer != nil) { - let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) + let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer!) let image = self.processPhoto(imageData!) // Call delegate and return new image @@ -916,38 +916,35 @@ open class SwiftyCamViewController: UIViewController { fileprivate func videoInputPresetFromVideoQuality(quality: VideoQuality) -> String { switch quality { - case .high: return AVCaptureSessionPresetHigh - case .medium: return AVCaptureSessionPresetMedium - case .low: return AVCaptureSessionPresetLow - case .resolution352x288: return AVCaptureSessionPreset352x288 - case .resolution640x480: return AVCaptureSessionPreset640x480 - case .resolution1280x720: return AVCaptureSessionPreset1280x720 - case .resolution1920x1080: return AVCaptureSessionPreset1920x1080 - case .iframe960x540: return AVCaptureSessionPresetiFrame960x540 - case .iframe1280x720: return AVCaptureSessionPresetiFrame1280x720 + case .high: return AVCaptureSession.Preset.high.rawValue + case .medium: return AVCaptureSession.Preset.medium.rawValue + case .low: return AVCaptureSession.Preset.low.rawValue + case .resolution352x288: return AVCaptureSession.Preset.cif352x288.rawValue + case .resolution640x480: return AVCaptureSession.Preset.vga640x480.rawValue + case .resolution1280x720: return AVCaptureSession.Preset.hd1280x720.rawValue + case .resolution1920x1080: return AVCaptureSession.Preset.hd1920x1080.rawValue + case .iframe960x540: return AVCaptureSession.Preset.iFrame960x540.rawValue + case .iframe1280x720: return AVCaptureSession.Preset.iFrame1280x720.rawValue case .resolution3840x2160: if #available(iOS 9.0, *) { - return AVCaptureSessionPreset3840x2160 + return AVCaptureSession.Preset.hd4K3840x2160.rawValue } else { print("[SwiftyCam]: Resolution 3840x2160 not supported") - return AVCaptureSessionPresetHigh + return AVCaptureSession.Preset.high.rawValue } } } /// Get Devices - fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevicePosition) -> AVCaptureDevice? { - if let devices = AVCaptureDevice.devices(withMediaType: mediaType) as? [AVCaptureDevice] { - return devices.filter({ $0.position == position }).first - } - return nil + fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? { + return AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType)).first } /// Enable or disable flash for photo - fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: AVCaptureFlashMode) { + fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: AVCaptureDevice.FlashMode) { do { try device.lockForConfiguration() device.flashMode = mode @@ -981,17 +978,17 @@ open class SwiftyCamViewController: UIViewController { return } - let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) + let device = AVCaptureDevice.default(for: AVMediaType.video) // Check if device has a flash if (device?.hasTorch)! { do { try device?.lockForConfiguration() - if (device?.torchMode == AVCaptureTorchMode.on) { - device?.torchMode = AVCaptureTorchMode.off + if (device?.torchMode == AVCaptureDevice.TorchMode.on) { + device?.torchMode = AVCaptureDevice.TorchMode.off self.isCameraTorchOn = false } else { do { - try device?.setTorchModeOnWithLevel(1.0) + try device?.setTorchModeOn(level: 1.0) self.isCameraTorchOn = true } catch { print("[SwiftyCam]: \(error)") @@ -1089,27 +1086,28 @@ extension SwiftyCamViewController : SwiftyCamButtonDelegate { extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { /// Process newly captured video and write it to temporary directory - - public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) { - if let currentBackgroundRecordingID = backgroundRecordingID { - backgroundRecordingID = UIBackgroundTaskInvalid - - if currentBackgroundRecordingID != UIBackgroundTaskInvalid { - UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) - } - } - if error != nil { - print("[SwiftyCam]: Movie file finishing error: \(error)") - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didFailToRecordVideo: error) + + public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { + if let currentBackgroundRecordingID = backgroundRecordingID { + backgroundRecordingID = UIBackgroundTaskInvalid + + if currentBackgroundRecordingID != UIBackgroundTaskInvalid { + UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) } - } else { - //Call delegate function with the URL of the outputfile - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didFinishProcessVideoAt: outputFileURL) - } - } - } + } + + if let currentError = error { + print("[SwiftyCam]: Movie file finishing error: \(currentError)") + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didFailToRecordVideo: currentError) + } + } else { + //Call delegate function with the URL of the outputfile + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didFinishProcessVideoAt: outputFileURL) + } + } + } } // Mark: UIGestureRecognizer Declarations @@ -1124,7 +1122,7 @@ extension SwiftyCamViewController { return } do { - let captureDevice = AVCaptureDevice.devices().first as? AVCaptureDevice + let captureDevice = AVCaptureDevice.devices().first try captureDevice?.lockForConfiguration() zoomScale = min(maxZoomScale, max(1.0, min(beginZoomScale * pinch.scale, captureDevice!.activeFormat.videoMaxZoomFactor))) @@ -1166,7 +1164,7 @@ extension SwiftyCamViewController { device.focusMode = .autoFocus } device.exposurePointOfInterest = focusPoint - device.exposureMode = AVCaptureExposureMode.continuousAutoExposure + device.exposureMode = AVCaptureDevice.ExposureMode.continuousAutoExposure device.unlockForConfiguration() //Call delegate function and pass in the location of the touch @@ -1199,7 +1197,7 @@ extension SwiftyCamViewController { let translationDifference = currentTranslation - previousPanTranslation do { - let captureDevice = AVCaptureDevice.devices().first as? AVCaptureDevice + let captureDevice = AVCaptureDevice.devices().first try captureDevice?.lockForConfiguration() let currentZoom = captureDevice?.videoZoomFactor ?? 0.0 From 9a2d279544afbd4fa31e919e94dab425a4333d89 Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 6 Sep 2017 13:50:01 -0600 Subject: [PATCH 08/18] Continued work --- DemoSwiftyCam/DemoSwiftyCam/ViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 69b087d..67b2b8f 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -15,6 +15,7 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF import UIKit +import AVFoundation class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { From 9df5997d1844b7ae298effcb554752eeb9dffa42 Mon Sep 17 00:00:00 2001 From: Andrew Walz Date: Wed, 6 Sep 2017 14:03:43 -0600 Subject: [PATCH 09/18] Changed objc inference --- DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index fed99d5..98f6080 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -378,6 +378,8 @@ SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -426,6 +428,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -440,7 +444,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -456,7 +460,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; From 04faa034e30a5093cff95e8c4bad4148872c6c8e Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:00:18 -0400 Subject: [PATCH 10/18] Move orientation logic to separate class --- Source/Orientation.swift | 94 ++++++++++++++++++++++++++++ Source/SwiftyCamViewController.swift | 72 +++------------------ 2 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 Source/Orientation.swift diff --git a/Source/Orientation.swift b/Source/Orientation.swift new file mode 100644 index 0000000..de74816 --- /dev/null +++ b/Source/Orientation.swift @@ -0,0 +1,94 @@ +/*Copyright (c) 2016, Andrew Walz. + + Redistribution and use in source and binary forms, with or without modification,are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +import Foundation +import AVFoundation +import UIKit + +protocol Orientation: class { + func getPreviewLayerOrientation() -> AVCaptureVideoOrientation + func getVideoOrientation() -> AVCaptureVideoOrientation? + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation + func start() + func stop() +} + +class DeviceOrientation : Orientation { + var deviceOrientation : UIDeviceOrientation? + var shouldUseDeviceOrientation: Bool = false + + func start() { + self.deviceOrientation = UIDevice.current.orientation + NotificationCenter.default.addObserver(self, selector: #selector(didRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + } + + func stop() { + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + self.deviceOrientation = nil + } + + @objc func didRotate() { + if !UIDevice.current.orientation.isFlat { + self.deviceOrientation = UIDevice.current.orientation + } + } + + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } + + switch deviceOrientation { + case .landscapeLeft: + return forCamera == .rear ? .up : .downMirrored + case .landscapeRight: + return forCamera == .rear ? .down : .upMirrored + case .portraitUpsideDown: + return forCamera == .rear ? .left : .rightMirrored + default: + return forCamera == .rear ? .right : .leftMirrored + } + } + + func getPreviewLayerOrientation() -> AVCaptureVideoOrientation { + // Depends on layout orientation, not device orientation + switch UIApplication.shared.statusBarOrientation { + case .portrait, .unknown: + return AVCaptureVideoOrientation.portrait + case .landscapeLeft: + return AVCaptureVideoOrientation.landscapeLeft + case .landscapeRight: + return AVCaptureVideoOrientation.landscapeRight + case .portraitUpsideDown: + return AVCaptureVideoOrientation.portraitUpsideDown + } + } + + func getVideoOrientation() -> AVCaptureVideoOrientation? { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return nil } + + switch deviceOrientation { + case .landscapeLeft: + return .landscapeRight + case .landscapeRight: + return .landscapeLeft + case .portraitUpsideDown: + return .portraitUpsideDown + default: + return .portrait + } + } +} + + + diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 4a7e743..7a8cc77 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -233,7 +233,7 @@ open class SwiftyCamViewController: UIViewController { /// PreviewView for the capture session - fileprivate var previewLayer : PreviewView! + var previewLayer : PreviewView! /// UIView for front facing flash @@ -245,7 +245,7 @@ open class SwiftyCamViewController: UIViewController { /// Last changed orientation - fileprivate var deviceOrientation : UIDeviceOrientation? + var orientation : Orientation = DeviceOrientation() /// Boolean to store when View Controller is notified session is running @@ -368,7 +368,7 @@ open class SwiftyCamViewController: UIViewController { // Subscribe to device rotation notifications if shouldUseDeviceOrientation { - subscribeToDeviceOrientationChangeNotifications() + orientation.start() } // Set background audio preference @@ -384,7 +384,7 @@ open class SwiftyCamViewController: UIViewController { // Preview layer video orientation can be set only after the connection is created DispatchQueue.main.async { - self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.getPreviewLayerOrientation() + self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.orientation.getPreviewLayerOrientation() } case .notAuthorized: @@ -424,7 +424,7 @@ open class SwiftyCamViewController: UIViewController { // Unsubscribe from device rotation notifications if shouldUseDeviceOrientation { - unsubscribeFromDeviceOrientationChangeNotifications() + orientation.stop() } } @@ -519,7 +519,7 @@ open class SwiftyCamViewController: UIViewController { movieFileOutputConnection?.isVideoMirrored = true } - movieFileOutputConnection?.videoOrientation = self.getVideoOrientation() + movieFileOutputConnection?.videoOrientation = self.orientation.getVideoOrientation() ?? self.previewLayer.videoPreviewLayer.connection!.videoOrientation // Start recording to a temporary file. let outputFileName = UUID().uuidString @@ -776,65 +776,7 @@ open class SwiftyCamViewController: UIViewController { /// Orientation management - fileprivate func subscribeToDeviceOrientationChangeNotifications() { - self.deviceOrientation = UIDevice.current.orientation - NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - } - fileprivate func unsubscribeFromDeviceOrientationChangeNotifications() { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - self.deviceOrientation = nil - } - - @objc fileprivate func deviceDidRotate() { - if !UIDevice.current.orientation.isFlat { - self.deviceOrientation = UIDevice.current.orientation - } - } - - fileprivate func getPreviewLayerOrientation() -> AVCaptureVideoOrientation { - // Depends on layout orientation, not device orientation - switch UIApplication.shared.statusBarOrientation { - case .portrait, .unknown: - return AVCaptureVideoOrientation.portrait - case .landscapeLeft: - return AVCaptureVideoOrientation.landscapeLeft - case .landscapeRight: - return AVCaptureVideoOrientation.landscapeRight - case .portraitUpsideDown: - return AVCaptureVideoOrientation.portraitUpsideDown - } - } - - fileprivate func getVideoOrientation() -> AVCaptureVideoOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection!.videoOrientation } - - switch deviceOrientation { - case .landscapeLeft: - return .landscapeRight - case .landscapeRight: - return .landscapeLeft - case .portraitUpsideDown: - return .portraitUpsideDown - default: - return .portrait - } - } - - fileprivate func getImageOrientation(forCamera: CameraSelection) -> UIImageOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } - - switch deviceOrientation { - case .landscapeLeft: - return forCamera == .rear ? .up : .downMirrored - case .landscapeRight: - return forCamera == .rear ? .down : .upMirrored - case .portraitUpsideDown: - return forCamera == .rear ? .left : .rightMirrored - default: - return forCamera == .rear ? .right : .leftMirrored - } - } /** Returns a UIImage from Image Data. @@ -851,7 +793,7 @@ open class SwiftyCamViewController: UIViewController { // Set proper orientation for photo // If camera is currently set to front camera, flip image - let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.getImageOrientation(forCamera: self.currentCamera)) + let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.orientation.getImageOrientation(forCamera: self.currentCamera)) return image } From a9746bf861e1fbbccf550249830f8517ae187717 Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:06:21 -0400 Subject: [PATCH 11/18] Ensure preview layer is accessed on main thread --- Source/SwiftyCamViewController.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 7a8cc77..9234bdc 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -503,6 +503,9 @@ open class SwiftyCamViewController: UIViewController { flashView?.alpha = 0.85 previewLayer.addSubview(flashView!) } + + //Must be fetched before on main thread + let previewOrientation = previewLayer.videoPreviewLayer.connection!.videoOrientation sessionQueue.async { [unowned self] in if !movieFileOutput.isRecording { @@ -519,7 +522,7 @@ open class SwiftyCamViewController: UIViewController { movieFileOutputConnection?.isVideoMirrored = true } - movieFileOutputConnection?.videoOrientation = self.orientation.getVideoOrientation() ?? self.previewLayer.videoPreviewLayer.connection!.videoOrientation + movieFileOutputConnection?.videoOrientation = self.orientation.getVideoOrientation() ?? previewOrientation // Start recording to a temporary file. let outputFileName = UUID().uuidString From 0c4b65f8aaac341ab77c803be1fcd544f7899e4c Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:10:01 -0400 Subject: [PATCH 12/18] Remove protocol for orientation mode --- Source/Orientation.swift | 12 +++--------- Source/SwiftyCamViewController.swift | 8 ++++++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Source/Orientation.swift b/Source/Orientation.swift index de74816..0611d22 100644 --- a/Source/Orientation.swift +++ b/Source/Orientation.swift @@ -17,17 +17,11 @@ import Foundation import AVFoundation import UIKit -protocol Orientation: class { - func getPreviewLayerOrientation() -> AVCaptureVideoOrientation - func getVideoOrientation() -> AVCaptureVideoOrientation? - func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation - func start() - func stop() -} -class DeviceOrientation : Orientation { - var deviceOrientation : UIDeviceOrientation? +class Orientation { + private var deviceOrientation : UIDeviceOrientation? var shouldUseDeviceOrientation: Bool = false + func start() { self.deviceOrientation = UIDevice.current.orientation diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 9234bdc..36c6695 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -145,7 +145,11 @@ open class SwiftyCamViewController: UIViewController { /// Sets wether the taken photo or video should be oriented according to the device orientation - public var shouldUseDeviceOrientation = false + public var shouldUseDeviceOrientation = false { + didSet { + orientation.shouldUseDeviceOrientation = shouldUseDeviceOrientation + } + } /// Sets whether or not View Controller supports auto rotation @@ -245,7 +249,7 @@ open class SwiftyCamViewController: UIViewController { /// Last changed orientation - var orientation : Orientation = DeviceOrientation() + var orientation = Orientation() /// Boolean to store when View Controller is notified session is running From a95a04a47573db89ec4187c1a0831fd7c37e5acd Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:21:15 -0400 Subject: [PATCH 13/18] Use core motion to calculate orientation --- Source/Orientation.swift | 42 +++++++++++++++++++++------- Source/SwiftyCamViewController.swift | 3 -- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Source/Orientation.swift b/Source/Orientation.swift index 0611d22..f51030e 100644 --- a/Source/Orientation.swift +++ b/Source/Orientation.swift @@ -16,29 +16,35 @@ import Foundation import AVFoundation import UIKit +import CoreMotion class Orientation { - private var deviceOrientation : UIDeviceOrientation? + var shouldUseDeviceOrientation: Bool = false - + + fileprivate var deviceOrientation : UIDeviceOrientation? + fileprivate let coreMotionManager = CMMotionManager() + + init() { + coreMotionManager.accelerometerUpdateInterval = 0.1 + } func start() { self.deviceOrientation = UIDevice.current.orientation - NotificationCenter.default.addObserver(self, selector: #selector(didRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + coreMotionManager.startAccelerometerUpdates(to: .main) { [weak self] (data, error) in + guard let data = data else { + return + } + self?.handleAccelerometerUpdate(data: data) + } } func stop() { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + self.coreMotionManager.stopAccelerometerUpdates() self.deviceOrientation = nil } - @objc func didRotate() { - if !UIDevice.current.orientation.isFlat { - self.deviceOrientation = UIDevice.current.orientation - } - } - func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation { guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } @@ -82,6 +88,22 @@ class Orientation { return .portrait } } + + private func handleAccelerometerUpdate(data: CMAccelerometerData){ + if(abs(data.acceleration.y) < abs(data.acceleration.x)){ + if(data.acceleration.x > 0){ + deviceOrientation = UIDeviceOrientation.landscapeRight + } else { + deviceOrientation = UIDeviceOrientation.landscapeLeft + } + } else{ + if(data.acceleration.y > 0){ + deviceOrientation = UIDeviceOrientation.portraitUpsideDown + } else { + deviceOrientation = UIDeviceOrientation.portrait + } + } + } } diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 36c6695..d54b78c 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -781,9 +781,6 @@ open class SwiftyCamViewController: UIViewController { } } - /// Orientation management - - /** Returns a UIImage from Image Data. From 995071a57425b4a0752676317465c00db4e87ede Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:23:26 -0400 Subject: [PATCH 14/18] Format code --- Source/SwiftyCamViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index d54b78c..42eb596 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -237,7 +237,7 @@ open class SwiftyCamViewController: UIViewController { /// PreviewView for the capture session - var previewLayer : PreviewView! + fileprivate var previewLayer : PreviewView! /// UIView for front facing flash @@ -249,7 +249,7 @@ open class SwiftyCamViewController: UIViewController { /// Last changed orientation - var orientation = Orientation() + fileprivate var orientation : Orientation = Orientation() /// Boolean to store when View Controller is notified session is running From fedb6ef39e3f07576117d71a658c2980c94f40a7 Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Wed, 18 Oct 2017 13:51:46 -0400 Subject: [PATCH 15/18] Ensure demo project can be compiled --- .../DemoSwiftyCam.xcodeproj/project.pbxproj | 15 ++++++++++----- SwiftyCam.podspec | 15 --------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index 98f6080..d020416 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 056AAB091F97CB1700F6A978 /* Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056AAB081F97CB1700F6A978 /* Orientation.swift */; }; + 056AAB0A1F97CB1E00F6A978 /* Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 056AAB081F97CB1700F6A978 /* Orientation.swift */; }; 05D2A9B81E80BE9700B479E9 /* SwiftyCam-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 05D2A9B61E80BE9700B479E9 /* SwiftyCam-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 05D2A9BC1E80BE9D00B479E9 /* PreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A9891E00A74A00B80903 /* PreviewView.swift */; }; 05D2A9BD1E80BE9D00B479E9 /* SwiftyCamButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98A1E00A74A00B80903 /* SwiftyCamButton.swift */; }; @@ -27,6 +29,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 056AAB081F97CB1700F6A978 /* Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Orientation.swift; path = ../../Source/Orientation.swift; sourceTree = ""; }; 05D2A9B41E80BE9700B479E9 /* SwiftyCam.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyCam.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 05D2A9B61E80BE9700B479E9 /* SwiftyCam-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftyCam-iOS.h"; sourceTree = ""; }; 05D2A9B71E80BE9700B479E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -111,6 +114,7 @@ 1675A9911E00A74F00B80903 /* Source */ = { isa = PBXGroup; children = ( + 056AAB081F97CB1700F6A978 /* Orientation.swift */, 1675A9891E00A74A00B80903 /* PreviewView.swift */, 1675A98A1E00A74A00B80903 /* SwiftyCamButton.swift */, 1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */, @@ -184,7 +188,6 @@ }; 1675A9711E00A68300B80903 = { CreatedOnToolsVersion = 8.1; - DevelopmentTeam = G8E5P2X66G; LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; @@ -235,6 +238,7 @@ buildActionMask = 2147483647; files = ( 05D2A9BC1E80BE9D00B479E9 /* PreviewView.swift in Sources */, + 056AAB0A1F97CB1E00F6A978 /* Orientation.swift in Sources */, 05D2A9BF1E80BE9D00B479E9 /* SwiftyCamViewControllerDelegate.swift in Sources */, 05D2A9BE1E80BE9D00B479E9 /* SwiftyCamViewController.swift in Sources */, 05D2A9BD1E80BE9D00B479E9 /* SwiftyCamButton.swift in Sources */, @@ -251,6 +255,7 @@ 1675A9761E00A68300B80903 /* AppDelegate.swift in Sources */, 1675A98F1E00A74A00B80903 /* SwiftyCamViewController.swift in Sources */, 168505EA1E288D80005B4537 /* PhotoViewController.swift in Sources */, + 056AAB091F97CB1700F6A978 /* Orientation.swift in Sources */, 16298B561E2703DC0056D413 /* SwiftyRecordButton.swift in Sources */, 1675A98D1E00A74A00B80903 /* PreviewView.swift in Sources */, 1675A98E1E00A74A00B80903 /* SwiftyCamButton.swift in Sources */, @@ -295,7 +300,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.Cappsule.SwiftyCam-iOS"; PRODUCT_NAME = SwiftyCam; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -318,7 +323,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.Cappsule.SwiftyCam-iOS"; PRODUCT_NAME = SwiftyCam; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -438,7 +443,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = G8E5P2X66G; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = DemoSwiftyCam/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -454,7 +459,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = G8E5P2X66G; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = DemoSwiftyCam/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/SwiftyCam.podspec b/SwiftyCam.podspec index 0b1ecee..1fcb90d 100644 --- a/SwiftyCam.podspec +++ b/SwiftyCam.podspec @@ -12,13 +12,6 @@ Pod::Spec.new do |s| s.summary = 'A Simple, Snapchat inspired camera Framework written in Swift' s.ios.deployment_target = '8.0' - -# This description is used to generate tags and improve search results. -# * Think: What does it do? Why did you write it? What is the focus? -# * Try to keep it short, snappy and to the point. -# * Write the description between the DESC delimiters below. -# * Finally, don't worry about the indent, CocoaPods strips it! - s.description = <<-DESC A drop in Camera View Controller for capturing photos and videos from one AVSession. Written in Swift. DESC @@ -33,12 +26,4 @@ A drop in Camera View Controller for capturing photos and videos from one AVSess s.ios.deployment_target = '8.0' s.source_files = 'Source/**/*' - - # s.resource_bundles = { - # 'SwiftyCam' => ['SwiftyCam/Assets/*.png'] - # } - - # s.public_header_files = 'Pod/Classes/**/*.h' - # s.frameworks = 'UIKit', 'MapKit' - # s.dependency 'AFNetworking', '~> 2.3' end From afd121afa2df70c732040348e592eb3bc2217d5a Mon Sep 17 00:00:00 2001 From: Vincent Castro Date: Sat, 28 Oct 2017 19:56:51 -0800 Subject: [PATCH 16/18] Fix for switching camera from front to back and back to front with addition for iOS 10 --- Source/SwiftyCamViewController.swift | 171 +++++++++++++++------------ 1 file changed, 93 insertions(+), 78 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 42eb596..b72d6da 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -112,7 +112,7 @@ open class SwiftyCamViewController: UIViewController { /// Sets the maximum zoom scale allowed during gestures gesture public var maxZoomScale = CGFloat.greatestFiniteMagnitude - + /// Sets whether Tap to Focus and Tap to Adjust Exposure is enabled for the capture session public var tapToFocus = true @@ -130,13 +130,13 @@ open class SwiftyCamViewController: UIViewController { /// Sets whether a double tap to switch cameras is supported public var doubleTapCameraSwitch = true - + /// Sets whether swipe vertically to zoom is supported - + public var swipeToZoom = true - + /// Sets whether swipe vertically gestures should be inverted - + public var swipeToZoomInverted = false /// Set default launch camera @@ -150,25 +150,25 @@ open class SwiftyCamViewController: UIViewController { orientation.shouldUseDeviceOrientation = shouldUseDeviceOrientation } } - + /// Sets whether or not View Controller supports auto rotation - + public var allowAutoRotate = false - + /// Specifies the [videoGravity](https://developer.apple.com/reference/avfoundation/avcapturevideopreviewlayer/1386708-videogravity) for the preview layer. public var videoGravity : SwiftyCamVideoGravity = .resizeAspect - + /// Sets whether or not video recordings will record audio /// Setting to true will prompt user for access to microphone on View Controller launch. public var audioEnabled = true - + /// Sets whether or not app should display prompt to app settings if audio/video permission is denied /// If set to false, delegate function will be called to handle exception public var shouldPrompToAppSettings = true - + /// Public access to Pinch Gesture fileprivate(set) public var pinchGesture : UIPinchGestureRecognizer! - + /// Public access to Pan Gesture fileprivate(set) public var panGesture : UIPanGestureRecognizer! @@ -242,17 +242,17 @@ open class SwiftyCamViewController: UIViewController { /// UIView for front facing flash fileprivate var flashView : UIView? - + /// Pan Translation - + fileprivate var previousPanTranslation : CGFloat = 0.0 /// Last changed orientation fileprivate var orientation : Orientation = Orientation() - + /// Boolean to store when View Controller is notified session is running - + fileprivate var sessionRunning = false /// Disable view autorotation for forced portrait recorindg @@ -272,7 +272,7 @@ open class SwiftyCamViewController: UIViewController { view.sendSubview(toBack: previewLayer) // Add Gesture Recognizers - + addGestureRecognizers() previewLayer.session = session @@ -303,72 +303,72 @@ open class SwiftyCamViewController: UIViewController { self.configureSession() } } - + // MARK: ViewDidLayoutSubviews - + /// ViewDidLayoutSubviews() Implementation private func updatePreviewLayer(layer: AVCaptureConnection, orientation: AVCaptureVideoOrientation) { - + layer.videoOrientation = orientation - + previewLayer.frame = self.view.bounds - + } - + override open func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - + if let connection = self.previewLayer?.videoPreviewLayer.connection { - + let currentDevice: UIDevice = UIDevice.current - + let orientation: UIDeviceOrientation = currentDevice.orientation - + let previewLayerConnection : AVCaptureConnection = connection - + if previewLayerConnection.isVideoOrientationSupported { - + switch (orientation) { case .portrait: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait) - + break - + case .landscapeRight: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeLeft) - + break - + case .landscapeLeft: updatePreviewLayer(layer: previewLayerConnection, orientation: .landscapeRight) - + break - + case .portraitUpsideDown: updatePreviewLayer(layer: previewLayerConnection, orientation: .portraitUpsideDown) - + break - + default: updatePreviewLayer(layer: previewLayerConnection, orientation: .portrait) - + break } } } } - + // MARK: ViewWillAppear - + /// ViewWillAppear(_ animated:) Implementation - + open override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(captureSessionDidStartRunning), name: .AVCaptureSessionDidStartRunning, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(captureSessionDidStopRunning), name: .AVCaptureSessionDidStopRunning, object: nil) } - + // MARK: ViewDidAppear /// ViewDidAppear(_ animated:) Implementation override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - + // Subscribe to device rotation notifications if shouldUseDeviceOrientation { @@ -385,12 +385,12 @@ open class SwiftyCamViewController: UIViewController { // Begin Session self.session.startRunning() self.isSessionRunning = self.session.isRunning - + // Preview layer video orientation can be set only after the connection is created DispatchQueue.main.async { self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.orientation.getPreviewLayerOrientation() } - + case .notAuthorized: if self.shouldPrompToAppSettings == true { self.promptToAppSettings() @@ -413,7 +413,7 @@ open class SwiftyCamViewController: UIViewController { override open func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + NotificationCenter.default.removeObserver(self) sessionRunning = false @@ -447,7 +447,7 @@ open class SwiftyCamViewController: UIViewController { guard let device = videoDevice else { return } - + if device.hasFlash == true && flashEnabled == true /* TODO: Add Support for Retina Flash and add front flash */ { changeFlashSettings(device: device, mode: .on) @@ -488,7 +488,7 @@ open class SwiftyCamViewController: UIViewController { */ public func startVideoRecording() { - + guard sessionRunning == true else { print("[SwiftyCam]: Cannot start video recoding. Capture session is not running") return @@ -507,7 +507,7 @@ open class SwiftyCamViewController: UIViewController { flashView?.alpha = 0.85 previewLayer.addSubview(flashView!) } - + //Must be fetched before on main thread let previewOrientation = previewLayer.videoPreviewLayer.connection!.videoOrientation @@ -587,11 +587,11 @@ open class SwiftyCamViewController: UIViewController { print("[SwiftyCam]: Switching between cameras while recording video is not supported") return } - + guard session.isRunning == true else { return } - + switch currentCamera { case .front: currentCamera = .rear @@ -803,12 +803,12 @@ open class SwiftyCamViewController: UIViewController { } fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) { - + guard sessionRunning == true else { print("[SwiftyCam]: Cannot take photo. Capture session is not running") return } - + if let videoConnection = photoFileOutput?.connection(with: AVMediaType.video) { photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in @@ -885,7 +885,26 @@ open class SwiftyCamViewController: UIViewController { /// Get Devices fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? { - return AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType)).first + if #available(iOS 10.0, *) { + let avDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType(rawValue: mediaType), position: position) + return avDevice + } else { + // Fallback on earlier versions + let avDevice = AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType)) + var avDeviceNum = 0 + for device in avDevice { + print("deviceWithMediaType Position: \(device.position.rawValue)") + if device.position == position { + break + } else { + avDeviceNum += 1 + } + } + + return avDevice[avDeviceNum] + } + + //return AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType), position: position).first } /// Enable or disable flash for photo @@ -953,7 +972,7 @@ open class SwiftyCamViewController: UIViewController { guard allowBackgroundAudio == true else { return } - + guard audioEnabled == true else { return } @@ -973,16 +992,16 @@ open class SwiftyCamViewController: UIViewController { } } - + /// Called when Notification Center registers session starts running - + @objc private func captureSessionDidStartRunning() { sessionRunning = true DispatchQueue.main.async { self.cameraDelegate?.swiftyCamSessionDidStartRunning(self) } } - + /// Called when Notification Center registers session stops running @objc private func captureSessionDidStopRunning() { @@ -1032,16 +1051,16 @@ extension SwiftyCamViewController : SwiftyCamButtonDelegate { extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { /// Process newly captured video and write it to temporary directory - + public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { if let currentBackgroundRecordingID = backgroundRecordingID { backgroundRecordingID = UIBackgroundTaskInvalid - + if currentBackgroundRecordingID != UIBackgroundTaskInvalid { UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) } } - + if let currentError = error { print("[SwiftyCam]: Movie file finishing error: \(currentError)") DispatchQueue.main.async { @@ -1064,7 +1083,7 @@ extension SwiftyCamViewController { @objc fileprivate func zoomGesture(pinch: UIPinchGestureRecognizer) { guard pinchToZoom == true && self.currentCamera == .rear else { - //ignore pinch + //ignore pinch return } do { @@ -1132,42 +1151,42 @@ extension SwiftyCamViewController { } switchCamera() } - + @objc private func panGesture(pan: UIPanGestureRecognizer) { - + guard swipeToZoom == true && self.currentCamera == .rear else { //ignore pan return } let currentTranslation = pan.translation(in: view).y let translationDifference = currentTranslation - previousPanTranslation - + do { - let captureDevice = AVCaptureDevice.devices().first + let captureDevice = AVCaptureDevice.devices().first try captureDevice?.lockForConfiguration() - + let currentZoom = captureDevice?.videoZoomFactor ?? 0.0 - + if swipeToZoomInverted == true { zoomScale = min(maxZoomScale, max(1.0, min(currentZoom - (translationDifference / 75), captureDevice!.activeFormat.videoMaxZoomFactor))) } else { zoomScale = min(maxZoomScale, max(1.0, min(currentZoom + (translationDifference / 75), captureDevice!.activeFormat.videoMaxZoomFactor))) } - + captureDevice?.videoZoomFactor = zoomScale - + // Call Delegate function with current zoom scale DispatchQueue.main.async { self.cameraDelegate?.swiftyCam(self, didChangeZoomLevel: self.zoomScale) } - + captureDevice?.unlockForConfiguration() - + } catch { print("[SwiftyCam]: Error locking configuration") } - + if pan.state == .ended || pan.state == .failed || pan.state == .cancelled { previousPanTranslation = 0.0 } else { @@ -1196,7 +1215,7 @@ extension SwiftyCamViewController { doubleTapGesture.numberOfTapsRequired = 2 doubleTapGesture.delegate = self previewLayer.addGestureRecognizer(doubleTapGesture) - + panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGesture(pan:))) panGesture.delegate = self previewLayer.addGestureRecognizer(panGesture) @@ -1217,7 +1236,3 @@ extension SwiftyCamViewController : UIGestureRecognizerDelegate { return true } } - - - - From c88e8f3d03213ba9104027962570af9ea722c1f8 Mon Sep 17 00:00:00 2001 From: Michael Prummer Date: Thu, 3 May 2018 10:43:39 +0200 Subject: [PATCH 17/18] Fixed optional checking for audio and video device (e.g. prevent crashing on the simulator) --- Source/SwiftyCamViewController.swift | 50 +++++++++++++++------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index b72d6da..bb48b20 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -712,18 +712,20 @@ open class SwiftyCamViewController: UIViewController { } do { - let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice!) - - if session.canAddInput(videoDeviceInput) { - session.addInput(videoDeviceInput) - self.videoDeviceInput = videoDeviceInput - } else { - print("[SwiftyCam]: Could not add video device input to the session") - print(session.canSetSessionPreset(AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: videoQuality)))) - setupResult = .configurationFailed - session.commitConfiguration() - return - } + if let videoDevice = videoDevice { + let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) + if session.canAddInput(videoDeviceInput) { + session.addInput(videoDeviceInput) + self.videoDeviceInput = videoDeviceInput + } else { + print("[SwiftyCam]: Could not add video device input to the session") + print(session.canSetSessionPreset(AVCaptureSession.Preset(rawValue: videoInputPresetFromVideoQuality(quality: videoQuality)))) + setupResult = .configurationFailed + session.commitConfiguration() + return + } + } + } catch { print("[SwiftyCam]: Could not create video device input: \(error)") setupResult = .configurationFailed @@ -738,17 +740,19 @@ open class SwiftyCamViewController: UIViewController { return } do { - let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio) - let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!) - - if session.canAddInput(audioDeviceInput) { - session.addInput(audioDeviceInput) - } - else { - print("[SwiftyCam]: Could not add audio device input to the session") - } - } - catch { + if let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio){ + let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) + if session.canAddInput(audioDeviceInput) { + session.addInput(audioDeviceInput) + } else { + print("[SwiftyCam]: Could not add audio device input to the session") + } + + } else { + print("[SwiftyCam]: Could not find an audio device") + } + + } catch { print("[SwiftyCam]: Could not create audio device input: \(error)") } } From 5c5931e86944d793eda6038fe5e8687a24afe460 Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Sun, 18 Nov 2018 20:40:56 -0500 Subject: [PATCH 18/18] Migrate swift from 4.0 to 4.2 --- .../DemoSwiftyCam.xcodeproj/project.pbxproj | 14 +++++++------ .../xcschemes/SwiftyCam-iOS.xcscheme | 4 +--- DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift | 2 +- .../DemoSwiftyCam/PhotoViewController.swift | 4 ++-- .../DemoSwiftyCam/VideoViewController.swift | 16 +++++++++++---- .../DemoSwiftyCam/ViewController.swift | 4 ++-- Source/Orientation.swift | 2 +- Source/SwiftyCamViewController.swift | 20 ++++++++++--------- 8 files changed, 38 insertions(+), 28 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index d020416..7872b96 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -179,7 +179,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = Cappsule; TargetAttributes = { 05D2A9B31E80BE9700B479E9 = { @@ -188,7 +188,7 @@ }; 1675A9711E00A68300B80903 = { CreatedOnToolsVersion = 8.1; - LastSwiftMigration = 0900; + LastSwiftMigration = 1010; ProvisioningStyle = Automatic; }; }; @@ -343,6 +343,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -350,6 +351,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -401,6 +403,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -408,6 +411,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -449,8 +453,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -465,8 +468,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme index b6c9ea0..f1c1bc6 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcshareddata/xcschemes/SwiftyCam-iOS.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift index dfee801..322b74d 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift @@ -22,7 +22,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } diff --git a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift index 4333a1f..1667af5 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift @@ -36,11 +36,11 @@ class PhotoViewController: UIViewController { super.viewDidLoad() self.view.backgroundColor = UIColor.gray let backgroundImageView = UIImageView(frame: view.frame) - backgroundImageView.contentMode = UIViewContentMode.scaleAspectFit + backgroundImageView.contentMode = UIView.ContentMode.scaleAspectFit backgroundImageView.image = backgroundImage view.addSubview(backgroundImageView) let cancelButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)) - cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState()) + cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControl.State()) cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) view.addSubview(cancelButton) } diff --git a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift index 0423a71..8121d1a 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift @@ -49,20 +49,23 @@ class VideoViewController: UIViewController { playerController!.showsPlaybackControls = false playerController!.player = player! - self.addChildViewController(playerController!) + self.addChild(playerController!) self.view.addSubview(playerController!.view) playerController!.view.frame = view.frame NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player!.currentItem) let cancelButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)) - cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState()) + cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControl.State()) cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) view.addSubview(cancelButton) // Allow background audio to continue to play do { - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient) + if #available(iOS 10.0, *) { + try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient, mode: .default, options: []) + } else { + } } catch let error as NSError { print(error) } @@ -85,8 +88,13 @@ class VideoViewController: UIViewController { @objc fileprivate func playerItemDidReachEnd(_ notification: Notification) { if self.player != nil { - self.player!.seek(to: kCMTimeZero) + self.player!.seek(to: CMTime.zero) self.player!.play() } } } + +// Helper function inserted by Swift 4.2 migrator. +fileprivate func convertFromAVAudioSessionCategory(_ input: AVAudioSession.Category) -> String { + return input.rawValue +} diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 67b2b8f..06a5d9b 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -153,9 +153,9 @@ extension ViewController { fileprivate func toggleFlashAnimation() { if flashEnabled == true { - flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControlState()) + flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControl.State()) } else { - flashButton.setImage(#imageLiteral(resourceName: "flashOutline"), for: UIControlState()) + flashButton.setImage(#imageLiteral(resourceName: "flashOutline"), for: UIControl.State()) } } } diff --git a/Source/Orientation.swift b/Source/Orientation.swift index f51030e..578d475 100644 --- a/Source/Orientation.swift +++ b/Source/Orientation.swift @@ -45,7 +45,7 @@ class Orientation { self.deviceOrientation = nil } - func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation { + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImage.Orientation { guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } switch deviceOrientation { diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index bb48b20..b03ecc5 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -269,7 +269,7 @@ open class SwiftyCamViewController: UIViewController { super.viewDidLoad() previewLayer = PreviewView(frame: view.frame, videoGravity: videoGravity) view.addSubview(previewLayer) - view.sendSubview(toBack: previewLayer) + view.sendSubviewToBack(previewLayer) // Add Gesture Recognizers @@ -845,9 +845,9 @@ open class SwiftyCamViewController: UIViewController { alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) alertController.addAction(UIAlertAction(title: NSLocalizedString("Settings", comment: "Alert button to open Settings"), style: .default, handler: { action in if #available(iOS 10.0, *) { - UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) + UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!) } else { - if let appSettings = URL(string: UIApplicationOpenSettingsURLString) { + if let appSettings = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.openURL(appSettings) } } @@ -983,12 +983,14 @@ open class SwiftyCamViewController: UIViewController { do{ if #available(iOS 10.0, *) { - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, - with: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP]) + try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP]) } else { - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, - with: [.mixWithOthers, .allowBluetooth]) + let options: [AVAudioSession.CategoryOptions] = [.mixWithOthers, .allowBluetooth] + let category = AVAudioSession.Category.playAndRecord + let selector = NSSelectorFromString("setCategory:withOptions:error:") + AVAudioSession.sharedInstance().perform(selector, with: category, with: options) } + try AVAudioSession.sharedInstance().setActive(true) session.automaticallyConfiguresApplicationAudioSession = false } catch { @@ -1058,9 +1060,9 @@ extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { if let currentBackgroundRecordingID = backgroundRecordingID { - backgroundRecordingID = UIBackgroundTaskInvalid + backgroundRecordingID = UIBackgroundTaskIdentifier.invalid - if currentBackgroundRecordingID != UIBackgroundTaskInvalid { + if currentBackgroundRecordingID != UIBackgroundTaskIdentifier.invalid { UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) } }