From 53ac26ee015b1ac4aa04afe3a5e288a5164ffff4 Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Sat, 10 Aug 2024 06:14:32 +0900 Subject: [PATCH 1/6] Devices --- .../LiveKit/Extensions/AVCaptureDevice.swift | 7 ++++- Sources/LiveKit/Extensions/TimeInterval.swift | 2 +- Sources/LiveKit/Support/DeviceManager.swift | 4 +++ .../Track/Capturers/CameraCapturer.swift | 4 +++ Tests/LiveKitTests/DeviceManager.swift | 31 +++++++++++++++++++ Tests/LiveKitTests/Support/Tracks.swift | 2 +- 6 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 Tests/LiveKitTests/DeviceManager.swift diff --git a/Sources/LiveKit/Extensions/AVCaptureDevice.swift b/Sources/LiveKit/Extensions/AVCaptureDevice.swift index c48293466..5fdf86026 100644 --- a/Sources/LiveKit/Extensions/AVCaptureDevice.swift +++ b/Sources/LiveKit/Extensions/AVCaptureDevice.swift @@ -18,12 +18,17 @@ import AVFoundation public extension AVCaptureDevice { /// Helper extension to return the acual direction the camera is facing. - /// In macOS, the Facetime camera's position is .unspecified but this property will return .front for such cases. var facingPosition: AVCaptureDevice.Position { #if os(macOS) + /// In macOS, the Facetime camera's position is .unspecified but this property will return .front for such cases. if deviceType == .builtInWideAngleCamera, position == .unspecified { return .front } + #elseif os(visionOS) + /// In visionOS, the Persona camera's position is .unspecified but this property will return .front for such cases. + if position == .unspecified { + return .front + } #endif return position diff --git a/Sources/LiveKit/Extensions/TimeInterval.swift b/Sources/LiveKit/Extensions/TimeInterval.swift index fac5db97b..e6bc1e61d 100644 --- a/Sources/LiveKit/Extensions/TimeInterval.swift +++ b/Sources/LiveKit/Extensions/TimeInterval.swift @@ -29,7 +29,7 @@ public extension TimeInterval { static let defaultPublisherDataChannelOpen: Self = 7 static let resolveSid: Self = 7 + 5 // Join response + 5 static let defaultPublish: Self = 10 - static let defaultCaptureStart: Self = 5 + static let defaultCaptureStart: Self = 10 } extension TimeInterval { diff --git a/Sources/LiveKit/Support/DeviceManager.swift b/Sources/LiveKit/Support/DeviceManager.swift index c1f96296e..fbd1b38d2 100644 --- a/Sources/LiveKit/Support/DeviceManager.swift +++ b/Sources/LiveKit/Support/DeviceManager.swift @@ -101,6 +101,10 @@ class DeviceManager: Loggable { self.devicesCompleter.resume(returning: devices) } } + #elseif os(visionOS) + // For visionOS, there is no DiscoverySession so return the Persona camera if available. + let devices: [AVCaptureDevice] = [.systemPreferredCamera].compactMap { $0 } + devicesCompleter.resume(returning: devices) #endif } } diff --git a/Sources/LiveKit/Track/Capturers/CameraCapturer.swift b/Sources/LiveKit/Track/Capturers/CameraCapturer.swift index 71564fcda..7539c93ff 100644 --- a/Sources/LiveKit/Track/Capturers/CameraCapturer.swift +++ b/Sources/LiveKit/Track/Capturers/CameraCapturer.swift @@ -222,6 +222,10 @@ public class CameraCapturer: VideoCapturer { log("starting camera capturer device: \(device), format: \(selectedFormat), fps: \(selectedFps)(\(fpsRange))", .info) + #if os(visionOS) + await AVCaptureDevice.requestAccess(for: .video) + #endif + try await capturer.startCapture(with: device, format: selectedFormat.format, fps: selectedFps) // Update internal vars diff --git a/Tests/LiveKitTests/DeviceManager.swift b/Tests/LiveKitTests/DeviceManager.swift new file mode 100644 index 000000000..25b8cb4e5 --- /dev/null +++ b/Tests/LiveKitTests/DeviceManager.swift @@ -0,0 +1,31 @@ +/* + * Copyright 2024 LiveKit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@testable import LiveKit +import XCTest + +class DeviceManagerTests: XCTestCase { + func testListDevices() async throws { + let devices = try await DeviceManager.shared.devices() + print("Devices: \(devices.map { "(facingPosition: \(String(describing: $0.facingPosition)))" }.joined(separator: ", "))") + XCTAssert(devices.count > 0, "No capture devices found.") + + // visionOS will return 0 formats. + guard let firstDevice = devices.first else { return } + let formats = firstDevice.formats + XCTAssert(formats.count > 0, "No formats found for device.") + } +} diff --git a/Tests/LiveKitTests/Support/Tracks.swift b/Tests/LiveKitTests/Support/Tracks.swift index d61b2740d..b0f6c5608 100644 --- a/Tests/LiveKitTests/Support/Tracks.swift +++ b/Tests/LiveKitTests/Support/Tracks.swift @@ -35,7 +35,7 @@ extension XCTestCase { let asset = AVAsset(url: tempLocalUrl) let assetReader = try AVAssetReader(asset: asset) - guard let track = asset.tracks(withMediaType: .video).first else { + guard let track = try await asset.loadTracks(withMediaType: .video).first else { XCTFail("No video track found in sample video file") fatalError() } From 41f2ed779304d100440024cf187881388f32d1fb Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:08:42 +0900 Subject: [PATCH 2/6] Use 125.6422.05 --- LiveKitClient.podspec | 2 +- Package.swift | 2 +- Package@swift-5.9.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LiveKitClient.podspec b/LiveKitClient.podspec index a9eaaec84..0163cd339 100644 --- a/LiveKitClient.podspec +++ b/LiveKitClient.podspec @@ -14,7 +14,7 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*" - spec.dependency("LiveKitWebRTC", "= 125.6422.03") + spec.dependency("LiveKitWebRTC", "= 125.6422.05") spec.dependency("SwiftProtobuf") spec.dependency("Logging") diff --git a/Package.swift b/Package.swift index b47f47323..9528c20be 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ let package = Package( ], dependencies: [ // LK-Prefixed Dynamic WebRTC XCFramework - .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.04"), + .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.05"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"), .package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"), // Only used for DocC generation diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift index 967a677fb..3ad8980ff 100644 --- a/Package@swift-5.9.swift +++ b/Package@swift-5.9.swift @@ -19,7 +19,7 @@ let package = Package( ], dependencies: [ // LK-Prefixed Dynamic WebRTC XCFramework - .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.04"), + .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.05"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"), .package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"), // Only used for DocC generation From d50dc5556805b03af451228182d65d2b129fc122 Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:09:59 +0900 Subject: [PATCH 3/6] Remove unnecessary requestAccess --- Sources/LiveKit/Track/Capturers/CameraCapturer.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/LiveKit/Track/Capturers/CameraCapturer.swift b/Sources/LiveKit/Track/Capturers/CameraCapturer.swift index 7539c93ff..71564fcda 100644 --- a/Sources/LiveKit/Track/Capturers/CameraCapturer.swift +++ b/Sources/LiveKit/Track/Capturers/CameraCapturer.swift @@ -222,10 +222,6 @@ public class CameraCapturer: VideoCapturer { log("starting camera capturer device: \(device), format: \(selectedFormat), fps: \(selectedFps)(\(fpsRange))", .info) - #if os(visionOS) - await AVCaptureDevice.requestAccess(for: .video) - #endif - try await capturer.startCapture(with: device, format: selectedFormat.format, fps: selectedFps) // Update internal vars From 5df96d54771fbdc6f651f84b9de308e507e210b4 Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:38:38 +0900 Subject: [PATCH 4/6] Fix Xcode 14.2 --- Tests/LiveKitTests/Support/Xcode14.2Backport.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift index ff15a4baa..9f44ce83a 100644 --- a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift +++ b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +import AVFoundation import Foundation import XCTest @@ -54,4 +55,10 @@ extension XCTestCase { } } } + +extension AVAsset { + func loadTracks(withMediaType mediaType: AVMediaType) async throws -> [AVAssetTrack] { + tracks(withMediaType: mediaType) + } +} #endif From e0a6cb9c8c5a1a8ed711cb1f8cf5fa20fd8bd0d1 Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Mon, 12 Aug 2024 18:06:00 +0900 Subject: [PATCH 5/6] Fix test load asset --- Tests/LiveKitTests/Support/Tracks.swift | 14 +++++++++++++- Tests/LiveKitTests/Support/Xcode14.2Backport.swift | 6 ------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Tests/LiveKitTests/Support/Tracks.swift b/Tests/LiveKitTests/Support/Tracks.swift index b0f6c5608..4dab733e9 100644 --- a/Tests/LiveKitTests/Support/Tracks.swift +++ b/Tests/LiveKitTests/Support/Tracks.swift @@ -35,7 +35,19 @@ extension XCTestCase { let asset = AVAsset(url: tempLocalUrl) let assetReader = try AVAssetReader(asset: asset) - guard let track = try await asset.loadTracks(withMediaType: .video).first else { + let tracks = try await { + #if os(visionOS) + return try await asset.loadTracks(withMediaType: .video) + #else + if #available(iOS 15.0, macOS 12.0, *) { + return try await asset.loadTracks(withMediaType: .video) + } else { + return asset.tracks(withMediaType: .video) + } + #endif + }() + + guard let track = tracks.first else { XCTFail("No video track found in sample video file") fatalError() } diff --git a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift index 9f44ce83a..3ba395a2c 100644 --- a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift +++ b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift @@ -55,10 +55,4 @@ extension XCTestCase { } } } - -extension AVAsset { - func loadTracks(withMediaType mediaType: AVMediaType) async throws -> [AVAssetTrack] { - tracks(withMediaType: mediaType) - } -} #endif From 9a54df6076bd557e3bd24f7661fed8522815093d Mon Sep 17 00:00:00 2001 From: hiroshihorie <548776+hiroshihorie@users.noreply.github.com> Date: Mon, 12 Aug 2024 18:09:08 +0900 Subject: [PATCH 6/6] Update Xcode14.2Backport.swift --- Tests/LiveKitTests/Support/Xcode14.2Backport.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift index 3ba395a2c..ff15a4baa 100644 --- a/Tests/LiveKitTests/Support/Xcode14.2Backport.swift +++ b/Tests/LiveKitTests/Support/Xcode14.2Backport.swift @@ -14,7 +14,6 @@ * limitations under the License. */ -import AVFoundation import Foundation import XCTest