// // 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.replay() } else { self.isPlaying = false self.delegate?.sp_playCompletion?(self) } } } }