Skip to content

Instantly share code, notes, and snippets.

@ajayjapan
Created December 11, 2025 12:24
Show Gist options
  • Select an option

  • Save ajayjapan/73231c1df38c620fc6bf89c3a5b036c7 to your computer and use it in GitHub Desktop.

Select an option

Save ajayjapan/73231c1df38c620fc6bf89c3a5b036c7 to your computer and use it in GitHub Desktop.
LiveStreamPreviewView.swift
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