session-ios/Session/Calls/UserInterface/LocalVideoView.swift

118 lines
3.6 KiB
Swift

//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
class LocalVideoView: UIView {
private let localVideoCapturePreview = RTCCameraPreviewView()
var captureSession: AVCaptureSession? {
set { localVideoCapturePreview.captureSession = newValue }
get { localVideoCapturePreview.captureSession }
}
override var contentMode: UIView.ContentMode {
didSet { localVideoCapturePreview.contentMode = contentMode }
}
override init(frame: CGRect) {
super.init(frame: .zero)
addSubview(localVideoCapturePreview)
if Platform.isSimulator {
backgroundColor = .green
}
NotificationCenter.default.addObserver(
self,
selector: #selector(updateLocalVideoOrientation),
name: UIDevice.orientationDidChangeNotification,
object: nil
)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var frame: CGRect {
didSet { updateLocalVideoOrientation() }
}
@objc
func updateLocalVideoOrientation() {
defer { localVideoCapturePreview.frame = bounds }
// iPad supports rotating this view controller directly,
// so we don't need to do anything here.
guard !UIDevice.current.isIPad else { return }
// We lock this view to portrait only on phones, but the
// local video capture will rotate with the device's
// orientation (so the remote party will render your video
// in the correct orientation). As such, we need to rotate
// the local video preview layer so it *looks* like we're
// also always capturing in portrait.
switch UIDevice.current.orientation {
case .portrait:
localVideoCapturePreview.transform = .identity
case .portraitUpsideDown:
localVideoCapturePreview.transform = .init(rotationAngle: .pi)
case .landscapeLeft:
localVideoCapturePreview.transform = .init(rotationAngle: .halfPi)
case .landscapeRight:
localVideoCapturePreview.transform = .init(rotationAngle: .pi + .halfPi)
case .faceUp, .faceDown, .unknown:
break
@unknown default:
break
}
}
}
extension RTCCameraPreviewView {
var previewLayer: AVCaptureVideoPreviewLayer? {
return layer as? AVCaptureVideoPreviewLayer
}
open override var contentMode: UIView.ContentMode {
set {
guard let previewLayer = previewLayer else {
return owsFailDebug("missing preview layer")
}
switch newValue {
case .scaleAspectFill:
previewLayer.videoGravity = .resizeAspectFill
case .scaleAspectFit:
previewLayer.videoGravity = .resizeAspect
case .scaleToFill:
previewLayer.videoGravity = .resize
default:
owsFailDebug("Unexpected contentMode")
}
}
get {
guard let previewLayer = previewLayer else {
owsFailDebug("missing preview layer")
return .scaleToFill
}
switch previewLayer.videoGravity {
case .resizeAspectFill:
return .scaleAspectFill
case .resizeAspect:
return .scaleAspectFit
case .resize:
return .scaleToFill
default:
owsFailDebug("Unexpected contentMode")
return .scaleToFill
}
}
}
}