Created
December 11, 2025 12:24
-
-
Save ajayjapan/73231c1df38c620fc6bf89c3a5b036c7 to your computer and use it in GitHub Desktop.
LiveStreamPreviewView.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| import AVFoundation | |
| import Observation | |
| import SwiftUI | |
| struct LiveStreamPreviewView: View { | |
| @State var cameraPreview = CameraPreviewModel() | |
| var body: some View { | |
| CameraPreviewView(session: cameraPreview.session) | |
| .onAppear { | |
| cameraPreview.setupCaptureSession() | |
| cameraPreview.startSession() | |
| } | |
| .onDisappear { | |
| cameraPreview.stopSession() | |
| } | |
| } | |
| } | |
| struct CameraPreviewView: UIViewRepresentable { | |
| let session: AVCaptureSession | |
| func makeUIView(context: Context) -> VideoPreviewView { | |
| let view = VideoPreviewView() | |
| view.videoPreviewLayer.session = session | |
| view.videoPreviewLayer.videoGravity = .resizeAspectFill | |
| return view | |
| } | |
| func updateUIView(_ uiView: VideoPreviewView, context: Context) {} | |
| } | |
| class VideoPreviewView: UIView { | |
| override class var layerClass: AnyClass { | |
| return AVCaptureVideoPreviewLayer.self | |
| } | |
| var videoPreviewLayer: AVCaptureVideoPreviewLayer { | |
| return layer as! AVCaptureVideoPreviewLayer | |
| } | |
| } | |
| @Observable | |
| class CameraPreviewModel { | |
| var session = AVCaptureSession() | |
| var videoDeviceInput: AVCaptureDeviceInput? | |
| var currentCameraPosition: AVCaptureDevice.Position = .front // Track the current camera position | |
| func checkPermissionsAndSetupSession() { | |
| let status = PermissionManager.queryCameraPermission() | |
| switch status { | |
| case .authorized, .limited: | |
| setupCaptureSession() | |
| case .unknown: | |
| Task { | |
| let result = await PermissionManager.requestCameraPermission() | |
| if result.isAuthorized == true { | |
| await MainActor.run { | |
| self.setupCaptureSession() | |
| } | |
| } | |
| } | |
| case .denied, .restricted: | |
| print("Camera access denied or restricted.") | |
| } | |
| } | |
| func setupCaptureSession() { | |
| session.beginConfiguration() | |
| // Video setup | |
| let videoPosition: AVCaptureDevice.Position = currentCameraPosition | |
| guard let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, | |
| for: .video, | |
| position: videoPosition) else { | |
| session.commitConfiguration() | |
| return | |
| } | |
| do { | |
| let videoInput = try AVCaptureDeviceInput(device: videoDevice) | |
| if session.canAddInput(videoInput) { | |
| session.addInput(videoInput) | |
| self.videoDeviceInput = videoInput | |
| } else { | |
| } | |
| } catch { | |
| } | |
| session.commitConfiguration() | |
| } | |
| func flipCamera() { | |
| guard let currentInput = videoDeviceInput else { return } | |
| // Toggle between front and back camera | |
| currentCameraPosition = currentCameraPosition == .front ? .back : .front | |
| let newPosition: AVCaptureDevice.Position = currentCameraPosition | |
| guard let newDevice = AVCaptureDevice.default(.builtInWideAngleCamera, | |
| for: .video, | |
| position: newPosition) else { | |
| return | |
| } | |
| session.beginConfiguration() | |
| session.removeInput(currentInput) | |
| do { | |
| let newVideoInput = try AVCaptureDeviceInput(device: newDevice) | |
| if session.canAddInput(newVideoInput) { | |
| session.addInput(newVideoInput) | |
| self.videoDeviceInput = newVideoInput | |
| } else { | |
| } | |
| } catch { | |
| } | |
| session.commitConfiguration() | |
| } | |
| func startSession() { | |
| DispatchQueue.global(qos: .userInitiated).async { [weak self] in | |
| self?.session.startRunning() | |
| } | |
| } | |
| func stopSession() { | |
| DispatchQueue.main.async { [weak self] in | |
| if let session = self?.session, session.isRunning { | |
| session.stopRunning() | |
| } else { | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment