【发布时间】:2021-08-30 17:00:54
【问题描述】:
我找到了OObject 的代码,它可以用作基本的音频播放器(带有滑块)
工作正常,但到目前为止我可以在ContentView 中使用它,如下所示:
@ObservedObject var player: AudioPlayerAV
let audioFileURL = URL(string: "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_5MG.mp3")
init(){
var playerItem = AVPlayerItem(url: audioFileURL!)
player = AudioPlayerAV(avPlayer: AVPlayer(playerItem: playerItem))
}
如果我有URL 或本地路径,我可以使用它。我不知道如何推迟初始化,例如,我想在同一 ContentView 中记录的元素上使用它。
//OObject
import AVFoundation
import Combine
let timeScale = CMTimeScale(1000)
let time = CMTime(seconds: 0.5, preferredTimescale: timeScale)
enum PlayerScrubState {
case reset
case scrubStarted
case scrubEnded(TimeInterval)
}
final class AudioPlayerAV: NSObject, ObservableObject {
@Published var displayTime: TimeInterval = 0
@Published var observedTime: TimeInterval = 0
@Published var itemDuration: TimeInterval = 0
@Published var audioFinishedPlaying: Bool = false
@Published var timeControlStatus: AVPlayer.TimeControlStatus = .paused
fileprivate var itemDurationKVOPublisher: AnyCancellable!
fileprivate var timeControlStatusKVOPublisher: AnyCancellable!
fileprivate var avPlayer: AVPlayer
fileprivate var periodicTimeObserver: Any?
var scrubState: PlayerScrubState = .reset {
didSet {
switch scrubState {
case .reset:
return
case .scrubStarted:
return
case .scrubEnded(let seekTime):
avPlayer.seek(to: CMTime(seconds: seekTime, preferredTimescale: 1000))
}
}
}
init(avPlayer: AVPlayer) {
self.avPlayer = avPlayer
super.init()
addPeriodicTimeObserver()
addTimeControlStatusObserver()
addItemDurationPublisher()
NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { (_) in
self.audioFinishedPlaying = true
}
}
deinit {
removePeriodicTimeObserver()
timeControlStatusKVOPublisher.cancel()
itemDurationKVOPublisher.cancel()
NotificationCenter.default.removeObserver(self)
}
func play() {
self.avPlayer.play()
}
func pause() {
self.avPlayer.pause()
}
fileprivate func addPeriodicTimeObserver() {
self.periodicTimeObserver = avPlayer.addPeriodicTimeObserver(forInterval: time, queue: .main) { [weak self] (time) in
guard let self = self else { return }
self.observedTime = time.seconds
switch self.scrubState {
case .reset:
self.displayTime = time.seconds
case .scrubStarted:
break
case .scrubEnded(let seekTime):
self.scrubState = .reset
self.displayTime = seekTime
}
}
}
fileprivate func removePeriodicTimeObserver() {
guard let periodicTimeObserver = self.periodicTimeObserver else {
return
}
avPlayer.removeTimeObserver(periodicTimeObserver)
self.periodicTimeObserver = nil
}
fileprivate func addTimeControlStatusObserver() {
timeControlStatusKVOPublisher = avPlayer
.publisher(for: \.timeControlStatus)
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] (newStatus) in
guard let self = self else { return }
self.timeControlStatus = newStatus
}
)
}
fileprivate func addItemDurationPublisher() {
itemDurationKVOPublisher = avPlayer
.publisher(for: \.currentItem?.duration)
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] (newStatus) in
guard let newStatus = newStatus,
let self = self else { return }
self.itemDuration = newStatus.seconds
}
)
}
}
【问题讨论】: