MoviaBox/ShortPlay/Libs/Player/SPPlayer.swift

255 lines
7.1 KiB
Swift

//
// SPPlayer.swift
// ShortPlay
//
// Created by on 2025/4/9.
//
import UIKit
import ZFPlayer
@objc protocol SPPlayerDelegate {
///
// @objc optional func sp_onDurationUpdate(_ player: SPPlayer, duration: Int)
//
// ///
// @objc optional func sp_onCurrentPositionUpdate(_ player: SPPlayer, position: Int)
///
@objc optional func sp_player(_ player: SPPlayer, playStateDidChanged state: SPPlayer.PlayState)
///
@objc optional func sp_playTimeChanged(_ player: SPPlayer, currentTime: Int, duration: Int)
///
@objc optional func sp_firstRenderedStart(_ player: SPPlayer)
///
@objc optional func sp_playCompletion(_ player: SPPlayer)
///
@objc optional func sp_playLoadingEnd(_ player: SPPlayer)
}
class SPPlayer: NSObject {
@objc enum PlayState: Int {
case unknown
case playing
case paused
case failed
case stopped
}
weak var delegate: SPPlayerDelegate?
private(set) lazy var isPlaying = false
private(set) lazy var playState: PlayState = .unknown
/**
*/
private var isAddIdleTimerDisabledObserver = false
///
var duration: Int {
return Int(self.player.totalTime)
}
///
var currentPosition: Int {
return Int(self.player.currentTime)
}
///0.5 - 2
var rate: Float {
set {
player.rate = newValue
}
get {
return player.rate
}
}
var playerView: UIView? {
didSet {
playerView?.addSubview(player.view)
player.view.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
private lazy var player: ZFAVPlayerManager = {
let player = ZFAVPlayerManager()
player.shouldAutoPlay = false
return player
}()
var isLoop = true
deinit {
self.stop()
}
override init() {
super.init()
player.scalingMode = .aspectFill
sp_addAction()
}
/**
*/
private func addIdleTimerDisabledObserver() {
if !isAddIdleTimerDisabledObserver {
isAddIdleTimerDisabledObserver = true
UIApplication.shared.addObserver(self, forKeyPath: "idleTimerDisabled", options: NSKeyValueObservingOptions.new, context: nil)
}
}
/**
*/
private func removeIdleTimerDisabledObserver() {
if isAddIdleTimerDisabledObserver {
isAddIdleTimerDisabledObserver = false
UIApplication.shared.removeObserver(self, forKeyPath: "idleTimerDisabled")
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if !UIApplication.shared.isIdleTimerDisabled {
UIApplication.shared.isIdleTimerDisabled = true
}
}
func setPlayUrl(url: String) {
let proxyURL = KTVHTTPCache.proxyURL(withOriginalURL: URL(string: url))
self.player.assetURL = proxyURL
// self.prepare()
}
///
func prepare() {
// self.player.prepareToPlay()
}
func stop() {
self.isPlaying = false
player.stop()
self.removeIdleTimerDisabledObserver()
UIApplication.shared.isIdleTimerDisabled = false
}
func start() {
self.isPlaying = true
player.play()
UIApplication.shared.isIdleTimerDisabled = true
self.addIdleTimerDisabledObserver()
}
///
func pause() {
self.isPlaying = false
player.pause()
self.removeIdleTimerDisabledObserver()
UIApplication.shared.isIdleTimerDisabled = false
}
///
func replay() {
self.isPlaying = true
self.player.replay()
UIApplication.shared.isIdleTimerDisabled = true
self.addIdleTimerDisabledObserver()
}
func seekToTime(toTime: Int) {
// self.player.seek(toTime: Int64(toTime), seekMode: AVP_SEEKMODE_ACCURATE)
self.player.seek(toTime: TimeInterval(toTime), completionHandler: nil)
}
}
extension SPPlayer {
private func sp_addAction() {
//
player.playerPlayTimeChanged = { [weak self] (asset, currentTime, duration) in
guard let self = self else { return }
self.delegate?.sp_playTimeChanged?(self, currentTime: Int(currentTime), duration: Int(duration))
}
//
player.playerPlayStateChanged = { [weak self] (asset, playState) in
guard let self = self else { return }
if playState == .playStatePlaying, !isPlaying {
self.pause()
} else if playState == .playStatePaused, isPlaying {
self.start()
}
switch playState {
case .playStateUnknown:
self.playState = .unknown
case .playStatePlaying:
self.playState = .playing
case .playStatePaused:
self.playState = .paused
case .playStatePlayStopped:
self.playState = .stopped
case .playStatePlayFailed:
self.playState = .failed
default:
self.playState = .unknown
}
self.delegate?.sp_player?(self, playStateDidChanged: self.playState)
spLog(message: "播放状态====\(playState)")
}
//
player.playerLoadStateChanged = { [weak self] (asset, loadState) in
guard let self = self else { return }
if loadState == .playable, !isPlaying {
self.pause()
} else if loadState == .playable, isPlaying, self.player.playState != .playStatePlaying {
self.start()
}
switch loadState {
case .prepare:
spLog(message: "加载状态====准备完成")
case .playable:
spLog(message: "加载状态====可播放")
case .playthroughOK:
spLog(message: "加载状态====将自动播放")
case .stalled:
spLog(message: "加载状态====如果已启动,将自动暂停")
default:
break
}
}
//
player.playerPlayFailed = { [weak self] (asset, error) in
spLog(message: "错误信息====\(error)")
}
//
player.playerDidToEnd = { [weak self] (asset) in
guard let self = self else { return }
if isLoop {
self.player.replay()
} else {
self.isPlaying = false
self.delegate?.sp_playCompletion?(self)
}
}
}
}