2022-05-19 07:29:25 -06:00
|
|
|
import AVFoundation
|
|
|
|
import AVKit
|
2023-12-07 00:47:40 -07:00
|
|
|
import Foundation
|
2022-05-19 07:29:25 -06:00
|
|
|
import MediaAccessibility
|
|
|
|
import React
|
|
|
|
|
2023-08-28 11:55:34 -06:00
|
|
|
#if os(iOS)
|
2023-12-07 00:47:40 -07:00
|
|
|
class RCTPictureInPicture: NSObject, AVPictureInPictureControllerDelegate {
|
2024-07-08 05:41:21 -06:00
|
|
|
public private(set) var _pipController: AVPictureInPictureController?
|
2024-03-26 07:10:31 -06:00
|
|
|
private var _onPictureInPictureEnter: (() -> Void)?
|
|
|
|
private var _onPictureInPictureExit: (() -> Void)?
|
2023-12-07 00:47:40 -07:00
|
|
|
private var _onRestoreUserInterfaceForPictureInPictureStop: (() -> Void)?
|
|
|
|
private var _restoreUserInterfaceForPIPStopCompletionHandler: ((Bool) -> Void)?
|
2025-01-04 04:37:33 -07:00
|
|
|
private var _isPictureInPictureActive: Bool {
|
|
|
|
return _pipController?.isPictureInPictureActive ?? false
|
|
|
|
}
|
2023-08-28 11:55:34 -06:00
|
|
|
|
2024-03-26 07:10:31 -06:00
|
|
|
init(
|
|
|
|
_ onPictureInPictureEnter: (() -> Void)? = nil,
|
|
|
|
_ onPictureInPictureExit: (() -> Void)? = nil,
|
|
|
|
_ onRestoreUserInterfaceForPictureInPictureStop: (() -> Void)? = nil
|
|
|
|
) {
|
|
|
|
_onPictureInPictureEnter = onPictureInPictureEnter
|
|
|
|
_onPictureInPictureExit = onPictureInPictureExit
|
2023-12-07 00:47:40 -07:00
|
|
|
_onRestoreUserInterfaceForPictureInPictureStop = onRestoreUserInterfaceForPictureInPictureStop
|
2023-11-20 00:43:35 -07:00
|
|
|
}
|
2023-12-07 00:47:40 -07:00
|
|
|
|
|
|
|
func pictureInPictureControllerDidStartPictureInPicture(_: AVPictureInPictureController) {
|
2024-03-26 07:10:31 -06:00
|
|
|
guard let _onPictureInPictureEnter else { return }
|
2023-12-07 00:47:40 -07:00
|
|
|
|
2024-03-26 07:10:31 -06:00
|
|
|
_onPictureInPictureEnter()
|
2023-12-07 00:47:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func pictureInPictureControllerDidStopPictureInPicture(_: AVPictureInPictureController) {
|
2024-03-26 07:10:31 -06:00
|
|
|
guard let _onPictureInPictureExit else { return }
|
2023-12-07 00:47:40 -07:00
|
|
|
|
2024-03-26 07:10:31 -06:00
|
|
|
_onPictureInPictureExit()
|
2023-12-07 00:47:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func pictureInPictureController(
|
|
|
|
_: AVPictureInPictureController,
|
|
|
|
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
|
|
|
|
) {
|
2024-01-04 12:16:23 -07:00
|
|
|
guard let _onRestoreUserInterfaceForPictureInPictureStop else { return }
|
2023-12-07 00:47:40 -07:00
|
|
|
|
|
|
|
_onRestoreUserInterfaceForPictureInPictureStop()
|
|
|
|
|
|
|
|
_restoreUserInterfaceForPIPStopCompletionHandler = completionHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
func setRestoreUserInterfaceForPIPStopCompletionHandler(_ restore: Bool) {
|
2024-01-04 12:16:23 -07:00
|
|
|
guard let _restoreUserInterfaceForPIPStopCompletionHandler else { return }
|
2023-12-07 00:47:40 -07:00
|
|
|
_restoreUserInterfaceForPIPStopCompletionHandler(restore)
|
|
|
|
self._restoreUserInterfaceForPIPStopCompletionHandler = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupPipController(_ playerLayer: AVPlayerLayer?) {
|
2024-01-23 23:54:58 -07:00
|
|
|
guard let playerLayer else { return }
|
|
|
|
if !AVPictureInPictureController.isPictureInPictureSupported() { return }
|
2023-12-07 00:47:40 -07:00
|
|
|
// Create new controller passing reference to the AVPlayerLayer
|
2024-01-23 23:54:58 -07:00
|
|
|
_pipController = AVPictureInPictureController(playerLayer: playerLayer)
|
2023-12-07 00:47:40 -07:00
|
|
|
if #available(iOS 14.2, *) {
|
|
|
|
_pipController?.canStartPictureInPictureAutomaticallyFromInline = true
|
|
|
|
}
|
|
|
|
_pipController?.delegate = self
|
2022-05-19 07:29:25 -06:00
|
|
|
}
|
2023-12-07 00:47:40 -07:00
|
|
|
|
2024-04-05 02:37:00 -06:00
|
|
|
func deinitPipController() {
|
|
|
|
_pipController = nil
|
|
|
|
}
|
|
|
|
|
2025-01-04 04:37:33 -07:00
|
|
|
func enterPictureInPicture() {
|
|
|
|
guard let _pipController else { return }
|
|
|
|
if !_isPictureInPictureActive {
|
|
|
|
_pipController.startPictureInPicture()
|
2023-12-07 00:47:40 -07:00
|
|
|
}
|
2025-01-04 04:37:33 -07:00
|
|
|
}
|
2023-12-07 00:47:40 -07:00
|
|
|
|
2025-01-04 04:37:33 -07:00
|
|
|
func exitPictureInPicture() {
|
2024-01-04 12:16:23 -07:00
|
|
|
guard let _pipController else { return }
|
2025-01-04 04:37:33 -07:00
|
|
|
if _isPictureInPictureActive {
|
|
|
|
let state = UIApplication.shared.applicationState
|
|
|
|
if state == .background || state == .inactive {
|
|
|
|
deinitPipController()
|
|
|
|
_onPictureInPictureExit?()
|
|
|
|
_onRestoreUserInterfaceForPictureInPictureStop?()
|
|
|
|
} else {
|
2023-12-07 00:47:40 -07:00
|
|
|
_pipController.stopPictureInPicture()
|
|
|
|
}
|
|
|
|
}
|
2022-05-19 07:29:25 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|