How GyroCam Handles Orientation
GyroCam continuously monitors device motion and adapts the video orientation. Below are simplified snippets from the Swift implementation.
startOrientationUpdates()
@MainActor func startOrientationUpdates() {
guard motionManager.isDeviceMotionAvailable else {
showError("Motion data unavailable")
return
}
if lockLandscape {
if previousOrientation == .portrait {
previousOrientation = .landscapeLeft
}
}
motionManager.deviceMotionUpdateInterval = 0.1
motionManager.startDeviceMotionUpdates(to: .main) { [weak self] motion, error in
guard let self = self else { return }
guard let motion = motion, error == nil else {
self.showError(error?.localizedDescription ?? "Motion updates failed")
return
}
let newOrientation = OrientationHelper.getOrientation(from: motion, currentOrientation: self.previousOrientation, cameraManager: self)
if newOrientation != self.previousOrientation && newOrientation != .unknown {
self.handleOrientationChange(newOrientation: newOrientation)
self.previousOrientation = newOrientation
}
DispatchQueue.main.async {
self.currentOrientation = newOrientation.description
self.updateVideoOrientation(newOrientation)
}
}
}
OrientationHelper.getOrientation()
struct OrientationHelper {
@MainActor static func getOrientation(from motion: CMDeviceMotion, currentOrientation: UIDeviceOrientation, cameraManager: CameraManager) -> UIDeviceOrientation {
let gravity = motion.gravity
let absX = abs(gravity.x)
let absY = abs(gravity.y)
let absZ = abs(gravity.z)
// Determine the real device orientation first
var realOrientation: UIDeviceOrientation = currentOrientation
// Check for landscape/portrait
if absX > absY {
// Landscape orientation
realOrientation = gravity.x > 0 ? .landscapeRight : .landscapeLeft
} else if absY > absX {
// Portrait orientation
realOrientation = gravity.y > 0 ? .portraitUpsideDown : .portrait
}
if cameraManager.useRealOrientation {
cameraManager.realOrientation = realOrientation.description
}
// If landscape lock is on, we need to determine what orientation to return
if cameraManager.lockLandscape {
// Skip face up/down check if locked to landscape
if absZ > max(absX, absY) {
if !cameraManager.useRealOrientation {
cameraManager.realOrientation = currentOrientation.description
}
return currentOrientation
}
// For landscape orientations, return the detected orientation
if absX > absY {
if !cameraManager.useRealOrientation {
cameraManager.realOrientation = gravity.x > 0 ? "Landscape Right" : "Landscape Left"
}
return gravity.x > 0 ? .landscapeRight : .landscapeLeft
} else if absY > absX {
if !cameraManager.useRealOrientation {
cameraManager.realOrientation = currentOrientation.description
}
return currentOrientation
} else {
if !cameraManager.useRealOrientation {
cameraManager.realOrientation = currentOrientation.description
}
return currentOrientation
}
} else {
cameraManager.realOrientation = realOrientation.description
return realOrientation
}
}
}
extension UIDeviceOrientation {
var description: String {
switch self {
case .portrait: return "Portrait"
case .portraitUpsideDown: return "Upside Down"
case .landscapeLeft: return "Landscape Left"
case .landscapeRight: return "Landscape Right"
case .faceUp: return "Face Up"
case .faceDown: return "Face Down"
default: return "Unknown"
}
}
}