Skip to content

Commit

Permalink
Support attachVideo() for visionOS.
Browse files Browse the repository at this point in the history
  • Loading branch information
shogo4405 committed Mar 27, 2024
1 parent 391f97c commit 6b24a7b
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 59 deletions.
2 changes: 0 additions & 2 deletions Examples/visionOS/ContentView.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import RealityKit
import RealityKitContent
import SwiftUI

struct ContentView: View {
Expand Down
4 changes: 0 additions & 4 deletions Sources/Extension/AVCaptureDevice+Extension.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#if os(iOS) || os(tvOS) || os(macOS)

import AVFoundation
import Foundation

Expand All @@ -21,5 +19,3 @@ extension AVCaptureDevice {
}
}
}

#endif
8 changes: 6 additions & 2 deletions Sources/Extension/AVCaptureDevice.Format+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ extension AVCaptureDevice.Format {
return true
}
}
#elseif os(visionOS)
extension AVCaptureDevice.Format {
var isMultiCamSupported: Bool {
return false
}
}
#endif

#if os(iOS) || os(tvOS) || os(macOS)
@available(tvOS 17.0, *)
extension AVCaptureDevice.Format {
func isFrameRateSupported(_ frameRate: Float64) -> Bool {
Expand All @@ -42,4 +47,3 @@ extension AVCaptureDevice.Format {
return false
}
}
#endif
4 changes: 2 additions & 2 deletions Sources/Extension/AVCaptureSession+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ extension AVCaptureSession {
}
}
}
#elseif os(iOS) || os(tvOS) || os(macOS)
#endif

@available(tvOS 17.0, *)
extension AVCaptureSession {
@available(iOS, obsoleted: 16.0)
Expand All @@ -35,5 +36,4 @@ extension AVCaptureSession {
}
}
}
#endif
// swiftlint:enable unused_setter_value
2 changes: 0 additions & 2 deletions Sources/Extension/AVFrameRateRange+Extension.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import AVFoundation
import Foundation

#if os(iOS) || os(tvOS) || os(macOS)
@available(tvOS 17.0, *)
extension AVFrameRateRange {
func clamp(rate: Float64) -> Float64 {
Expand All @@ -12,4 +11,3 @@ extension AVFrameRateRange {
(minFrameRate...maxFrameRate) ~= frameRate
}
}
#endif
43 changes: 26 additions & 17 deletions Sources/IO/IOCaptureSession.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#if os(iOS) || os(tvOS) || os(macOS)
import AVFoundation

protocol IOCaptureSessionDelegate: AnyObject {
@available(tvOS 17.0, *)
func captureSession(_ session: IOCaptureSession, sessionRuntimeError session: AVCaptureSession, error: AVError)
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@available(tvOS 17.0, *)
func captureSession(_ session: IOCaptureSession, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?)
@available(tvOS 17.0, *)
Expand All @@ -21,8 +20,10 @@ final class IOCaptureSession {
return false
}
}
#else
#elseif os(macOS)
static let isMultiCamSupported = true
#elseif os(visionOS)
static let isMultiCamSupported = false
#endif

#if os(iOS) || os(tvOS)
Expand All @@ -39,9 +40,12 @@ final class IOCaptureSession {
var isMultitaskingCameraAccessEnabled: Bool {
return session.isMultitaskingCameraAccessEnabled
}
#else
#elseif os(macOS)
let isMultiCamSessionEnabled = true
let isMultitaskingCameraAccessEnabled = true
#elseif os(visionOS)
let isMultiCamSessionEnabled = false
let isMultitaskingCameraAccessEnabled = false
#endif

weak var delegate: (any IOCaptureSessionDelegate)?
Expand Down Expand Up @@ -76,7 +80,10 @@ final class IOCaptureSession {
session.commitConfiguration()
}
}
#elseif os(iOS) || os(macOS)
#elseif os(visionOS)
/// The capture session instance.
private(set) lazy var session = AVCaptureSession()
#else
var sessionPreset: AVCaptureSession.Preset = .default {
didSet {
guard sessionPreset != oldValue, session.canSetSessionPreset(sessionPreset) else {
Expand Down Expand Up @@ -125,6 +132,7 @@ final class IOCaptureSession {

@available(tvOS 17.0, *)
func attachCapture(_ capture: any IOCaptureUnit) {
#if !os(visionOS)
if let connection = capture.connection {
if let input = capture.input, session.canAddInput(input) {
session.addInputWithNoConnections(input)
Expand All @@ -135,23 +143,26 @@ final class IOCaptureSession {
if session.canAddConnection(connection) {
session.addConnection(connection)
}
} else {
if let input = capture.input, session.canAddInput(input) {
session.addInput(input)
}
if let output = capture.output, session.canAddOutput(output) {
session.addOutput(output)
}
return
}
#endif
if let input = capture.input, session.canAddInput(input) {
session.addInput(input)
}
if let output = capture.output, session.canAddOutput(output) {
session.addOutput(output)
}
}

@available(tvOS 17.0, *)
func detachCapture(_ capture: any IOCaptureUnit) {
#if !os(visionOS)
if let connection = capture.connection {
if capture.output?.connections.contains(connection) == true {
session.removeConnection(connection)
}
}
#endif
if let input = capture.input, session.inputs.contains(input) {
session.removeInput(input)
}
Expand Down Expand Up @@ -199,15 +210,15 @@ final class IOCaptureSession {
@available(tvOS 17.0, *)
private func addSessionObservers(_ session: AVCaptureSession) {
NotificationCenter.default.addObserver(self, selector: #selector(sessionRuntimeError(_:)), name: .AVCaptureSessionRuntimeError, object: session)
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
NotificationCenter.default.addObserver(self, selector: #selector(sessionInterruptionEnded(_:)), name: .AVCaptureSessionInterruptionEnded, object: session)
NotificationCenter.default.addObserver(self, selector: #selector(sessionWasInterrupted(_:)), name: .AVCaptureSessionWasInterrupted, object: session)
#endif
}

@available(tvOS 17.0, *)
private func removeSessionObservers(_ session: AVCaptureSession) {
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
NotificationCenter.default.removeObserver(self, name: .AVCaptureSessionWasInterrupted, object: session)
NotificationCenter.default.removeObserver(self, name: .AVCaptureSessionInterruptionEnded, object: session)
#endif
Expand All @@ -234,7 +245,7 @@ final class IOCaptureSession {
delegate?.captureSession(self, sessionRuntimeError: session, error: error)
}

#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@available(tvOS 17.0, *)
@objc
private func sessionWasInterrupted(_ notification: Notification) {
Expand Down Expand Up @@ -286,5 +297,3 @@ extension IOCaptureSession: Running {
}
}
}

#endif
2 changes: 0 additions & 2 deletions Sources/IO/IOCaptureUnit.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#if os(iOS) || os(tvOS) || os(macOS)
import AVFoundation
import Foundation

Expand All @@ -14,4 +13,3 @@ protocol IOCaptureUnit {
var output: Output? { get set }
var connection: AVCaptureConnection? { get set }
}
#endif
12 changes: 5 additions & 7 deletions Sources/IO/IOMixer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ protocol IOMixerDelegate: AnyObject {
func mixer(_ mixer: IOMixer, didOutput video: CMSampleBuffer)
func mixer(_ mixer: IOMixer, videoErrorOccurred error: IOVideoUnitError)
func mixer(_ mixer: IOMixer, audioErrorOccurred error: IOAudioUnitError)
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@available(tvOS 17.0, *)
func mixer(_ mixer: IOMixer, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?)
@available(tvOS 17.0, *)
Expand Down Expand Up @@ -41,13 +41,11 @@ final class IOMixer {
return videoIO
}()

#if os(iOS) || os(tvOS) || os(macOS)
private(set) lazy var session = {
var session = IOCaptureSession()
session.delegate = self
return session
}()
#endif

private(set) lazy var audioEngine: AVAudioEngine? = {
return IOStream.audioEngineHolder.retain()
Expand All @@ -57,7 +55,7 @@ final class IOMixer {
IOStream.audioEngineHolder.release(audioEngine)
}

#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
func setBackgroundMode(_ background: Bool) {
guard #available(tvOS 17.0, *) else {
return
Expand Down Expand Up @@ -135,11 +133,11 @@ extension IOMixer: AudioCodecDelegate {
}
}

#if os(iOS) || os(tvOS) || os(macOS)
extension IOMixer: IOCaptureSessionDelegate {
// MARK: IOCaptureSessionDelegate
@available(tvOS 17.0, *)
func captureSession(_ capture: IOCaptureSession, sessionRuntimeError session: AVCaptureSession, error: AVError) {
#if os(iOS) || os(tvOS) || os(macOS)
switch error.code {
case .unsupportedDeviceActiveFormat:
guard let device = error.device, let format = device.videoFormat(
Expand All @@ -165,9 +163,10 @@ extension IOMixer: IOCaptureSessionDelegate {
default:
break
}
#endif
}

#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@available(tvOS 17.0, *)
func captureSession(_ _: IOCaptureSession, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?) {
delegate?.mixer(self, sessionWasInterrupted: session, reason: reason)
Expand All @@ -179,7 +178,6 @@ extension IOMixer: IOCaptureSessionDelegate {
}
#endif
}
#endif

extension IOMixer: IOAudioUnitDelegate {
// MARK: IOAudioUnitDelegate
Expand Down
15 changes: 5 additions & 10 deletions Sources/IO/IOStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public protocol IOStreamDelegate: AnyObject {
func stream(_ stream: IOStream, didOutput audio: AVAudioBuffer, when: AVAudioTime)
/// Tells the receiver to a video incoming.
func stream(_ stream: IOStream, didOutput video: CMSampleBuffer)
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
/// Tells the receiver to session was interrupted.
@available(tvOS 17.0, *)
func stream(_ stream: IOStream, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?)
Expand Down Expand Up @@ -290,11 +290,9 @@ open class IOStream: NSObject {
guard #available(tvOS 17.0, *) else {
return
}
#if os(iOS) || os(tvOS) || os(macOS)
if newValue != nil && self.mixer.videoIO.hasDevice {
self.mixer.session.startRunning()
}
#endif
}
}
}
Expand Down Expand Up @@ -332,13 +330,12 @@ open class IOStream: NSObject {
/// Creates a NetStream object.
override public init() {
super.init()
#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
#endif
}

#if os(iOS) || os(macOS) || os(tvOS)
/// Attaches the primary camera object.
/// - Warning: This method can't use appendSampleBuffer at the same time.
@available(tvOS 17.0, *)
Expand Down Expand Up @@ -387,6 +384,7 @@ open class IOStream: NSObject {
}
}

#if os(iOS) || os(macOS) || os(tvOS)
/// Attaches the audio capture object.
/// - Warning: This method can't use appendSampleBuffer at the same time.
@available(tvOS 17.0, *)
Expand Down Expand Up @@ -483,10 +481,7 @@ open class IOStream: NSObject {
mixer.muxer = telly
mixer.startRunning()
case .publish:
#if os(iOS) || os(tvOS) || os(macOS)
// Start capture audio and video data.
mixer.session.startRunning()
#endif
case .publishing(let muxer):
mixer.muxer = muxer
mixer.startRunning()
Expand All @@ -495,7 +490,7 @@ open class IOStream: NSObject {
}
}

#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@objc
private func didEnterBackground(_ notification: Notification) {
// Require main thread. Otherwise the microphone cannot be used in the background.
Expand Down Expand Up @@ -529,7 +524,7 @@ extension IOStream: IOMixerDelegate {
delegate?.stream(self, videoErrorOccurred: error)
}

#if os(iOS) || os(tvOS)
#if os(iOS) || os(tvOS) || os(visionOS)
@available(tvOS 17.0, *)
func mixer(_ mixer: IOMixer, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?) {
delegate?.stream(self, sessionWasInterrupted: session, reason: reason)
Expand Down
Loading

0 comments on commit 6b24a7b

Please sign in to comment.