Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add visionOS support #3425

Merged
merged 7 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions ios/Video/Features/RCTPlayerObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate {

_playerRateChangeObserver = player.observe(\.rate, options: [.old], changeHandler: _handlers.handlePlaybackRateChange)
_playerVolumeChangeObserver = player.observe(\.volume, options: [.old], changeHandler: _handlers.handleVolumeChange)
_playerExternalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange)
#if !os(visionOS)
KrzysztofMoch marked this conversation as resolved.
Show resolved Hide resolved
_playerExternalPlaybackActiveObserver = player.observe(\.isExternalPlaybackActive, changeHandler: _handlers.handleExternalPlaybackActiveChange)
#endif
}

func removePlayerObservers() {
Expand Down Expand Up @@ -151,11 +153,13 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate {
func addPlayerViewControllerObservers() {
guard let playerViewController, let _handlers else { return }

_playerViewControllerReadyForDisplayObserver = playerViewController.observe(
\.isReadyForDisplay,
options: [.new],
changeHandler: _handlers.handleReadyForDisplay
)
#if !os(visionOS)
_playerViewControllerReadyForDisplayObserver = playerViewController.observe(
\.isReadyForDisplay,
KrzysztofMoch marked this conversation as resolved.
Show resolved Hide resolved
options: [.new],
changeHandler: _handlers.handleReadyForDisplay
)
#endif

_playerViewControllerOverlayFrameObserver = playerViewController.contentOverlayView?.observe(
\.frame,
Expand Down
31 changes: 14 additions & 17 deletions ios/Video/Features/RCTVideoDRM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,21 @@ enum RCTVideoDRM {
contentIdData: Data
) -> Promise<Data> {
return Promise<Data>(on: .global()) { fulfill, reject in
var spcError: NSError!
var spcData: Data?
do {
spcData = try loadingRequest.streamingContentKeyRequestData(forApp: certificateData, contentIdentifier: contentIdData as Data, options: nil)
} catch _ {
print("SPC error")
}

if spcError != nil {
reject(spcError)
}

guard let spcData else {
reject(RCTVideoErrorHandler.noSPC)
return
}
#if os(visionOS)
// TODO: DRM is not supported yet on visionOS. See #3467
reject(NSError(domain: "DRM is not supported yet on visionOS", code: 0, userInfo: nil))
#else
guard let spcData = try? loadingRequest.streamingContentKeyRequestData(
forApp: certificateData,
contentIdentifier: contentIdData as Data,
options: nil
) else {
reject(RCTVideoErrorHandler.noSPC)
return
}

fulfill(spcData)
fulfill(spcData)
#endif
}
}

Expand Down
8 changes: 5 additions & 3 deletions ios/Video/Features/RCTVideoUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ enum RCTVideoAssetsUtils {
asset.loadTracks(withMediaType: withMediaType, completionHandler: handler)
}
} else {
return Promise { fulfill, _ in
fulfill(asset.tracks(withMediaType: withMediaType))
}
#if !os(visionOS)
return Promise { fulfill, _ in
fulfill(asset.tracks(withMediaType: withMediaType))
}
#endif
}
}
}
Expand Down
26 changes: 14 additions & 12 deletions ios/Video/RCTVideo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc
func setAllowsExternalPlayback(_ allowsExternalPlayback: Bool) {
_allowsExternalPlayback = allowsExternalPlayback
_player?.allowsExternalPlayback = _allowsExternalPlayback
#if !os(visionOS)
_player?.allowsExternalPlayback = _allowsExternalPlayback
#endif
}

@objc
Expand Down Expand Up @@ -642,7 +644,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
RCTPlayerOperations.configureAudio(ignoreSilentSwitch: _ignoreSilentSwitch, mixWithOthers: _mixWithOthers, audioOutput: _audioOutput)
do {
if audioOutput == "speaker" {
#if os(iOS)
#if os(iOS) || os(visionOS)
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
#endif
} else if audioOutput == "earpiece" {
Expand Down Expand Up @@ -713,7 +715,9 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
}

if #available(iOS 12.0, tvOS 12.0, *) {
_player?.preventsDisplaySleepDuringVideoPlayback = _preventsDisplaySleepDuringVideoPlayback
#if !os(visionOS)
_player?.preventsDisplaySleepDuringVideoPlayback = _preventsDisplaySleepDuringVideoPlayback
#endif
} else {
// Fallback on earlier versions
}
Expand Down Expand Up @@ -972,12 +976,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
}

let filter: CIFilter! = CIFilter(name: filterName)
if #available(iOS 9.0, *), let _playerItem {
RCTVideoUtils.generateVideoComposition(asset: _playerItem.asset, filter: filter).then { [weak self] composition in
self?._playerItem?.videoComposition = composition
}
} else {
// Fallback on earlier versions
RCTVideoUtils.generateVideoComposition(asset: _playerItem!.asset, filter: filter).then { [weak self] composition in
self?._playerItem?.videoComposition = composition
}
}

Expand Down Expand Up @@ -1280,9 +1280,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
}

func handleExternalPlaybackActiveChange(player _: AVPlayer, change _: NSKeyValueObservedChange<Bool>) {
guard let _player else { return }
onVideoExternalPlaybackChange?(["isExternalPlaybackActive": NSNumber(value: _player.isExternalPlaybackActive),
"target": reactTag as Any])
#if !os(visionOS)
guard let _player else { return }
onVideoExternalPlaybackChange?(["isExternalPlaybackActive": NSNumber(value: _player.isExternalPlaybackActive),
"target": reactTag as Any])
#endif
}

func handleViewControllerOverlayViewFrameChange(overlayView _: UIView, change: NSKeyValueObservedChange<CGRect>) {
Expand Down
41 changes: 41 additions & 0 deletions ios/patches/PromisesObjC.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Pod::Spec.new do |s|
KrzysztofMoch marked this conversation as resolved.
Show resolved Hide resolved
s.name = 'PromisesObjC'
s.version = '2.3.1.1'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache-2.0', :file => 'LICENSE' }
s.homepage = 'https://github.com/google/promises'
s.source = { :git => 'https://github.com/google/promises.git', :tag => '2.3.1' }
s.summary = 'Synchronization construct for Objective-C'
s.description = <<-DESC

Promises is a modern framework that provides a synchronization construct for
Objective-C to facilitate writing asynchronous code.
DESC

s.platforms = { :ios => '9.0', :osx => '10.11', :tvos => '9.0', :watchos => '2.0', :visionos => '1.0' }

s.module_name = 'FBLPromises'
s.prefix_header_file = false
s.header_dir = "./"
s.public_header_files = "Sources/#{s.module_name}/include/**/*.h"
s.private_header_files = "Sources/#{s.module_name}/include/FBLPromisePrivate.h"
s.source_files = "Sources/#{s.module_name}/**/*.{h,m}"
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES'
}

s.test_spec 'Tests' do |ts|
# Note: Omits watchOS as a workaround since XCTest is not available to watchOS for now.
# Reference: https://github.com/CocoaPods/CocoaPods/issues/8283, https://github.com/CocoaPods/CocoaPods/issues/4185.
ts.platforms = {:ios => nil, :osx => nil, :tvos => nil}
ts.source_files = "Tests/#{s.module_name}Tests/*.m",
"Sources/#{s.module_name}TestHelpers/include/#{s.module_name}TestHelpers.h"
end
s.test_spec 'PerformanceTests' do |ts|
# Note: Omits watchOS as a workaround since XCTest is not available to watchOS for now.
# Reference: https://github.com/CocoaPods/CocoaPods/issues/8283, https://github.com/CocoaPods/CocoaPods/issues/4185.
ts.platforms = {:ios => nil, :osx => nil, :tvos => nil}
ts.source_files = "Tests/#{s.module_name}PerformanceTests/*.m",
"Sources/#{s.module_name}TestHelpers/include/#{s.module_name}TestHelpers.h"
end
end
21 changes: 21 additions & 0 deletions ios/patches/PromisesSwift.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Pod::Spec.new do |s|
s.name = 'PromisesSwift'
s.version = '2.3.1.1'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache-2.0', :file => 'LICENSE' }
s.homepage = 'https://github.com/google/promises'
s.source = { :git => 'https://github.com/google/promises.git', :tag => '2.3.1' }
s.summary = 'Synchronization construct for Swift'
s.description = <<-DESC

Promises is a modern framework that provides a synchronization construct for
Swift to facilitate writing asynchronous code.
DESC

s.platforms = { :ios => '9.0', :osx => '10.11', :tvos => '9.0', :watchos => '2.0', :visionos => '1.0' }
s.swift_versions = ['5.0', '5.2']

s.module_name = 'Promises'
s.source_files = "Sources/#{s.module_name}/*.{swift}"
s.dependency 'PromisesObjC', "#{s.version}"
end
7 changes: 3 additions & 4 deletions react-native-video.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ Pod::Spec.new do |s|
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = 'https://github.com/react-native-video/react-native-video'
s.source = { :git => "https://github.com/react-native-video/react-native-video.git", :tag => "v#{s.version}" }

s.ios.deployment_target = "9.0"
s.tvos.deployment_target = "10.0"
s.homepage = 'https://github.com/react-native-video/react-native-video'
s.source = { :git => "https://github.com/react-native-video/react-native-video.git", :tag => "v#{s.version}" }
s.platforms = { :ios => "9.0", :tvos => "10.0", :visionos => "1.0" }

s.subspec "Video" do |ss|
ss.source_files = "ios/Video/**/*.{h,m,swift}"
Expand Down
Loading