Swift 5: AVPlayer 将多个音频文件相互叠加
Swift 5: AVPlayer layers multiple audio files on each other
我正在构建一个 Swift 5 音乐应用程序,其中 table 视图加载并列出 JSON API 中的多个对象。单击条目后,导航器会调用 selected 项目的详细视图。
在下方,您可以看到我的详细视图控制器,名为 BroadcastDetailViewController
。如您所见,有一个 playBroadcastButton
将播放音频文件并设置 AVAudioSession
。
到目前为止一切顺利。但是在我实现了通过控制中心擦洗器 (commandCenter.changePlaybackPositionCommand.addTarget
) 擦洗音频文件并返回到我的 table 视图控制器和 select 另一个项目来播放它的音频文件的可能性之后, AVPlayer 将多个音频文件相互叠加并同时播放。这是我不想要的行为。在我实现控制按钮之前,整个音频文件替换过程运行良好。
我的问题是,为什么播放器突然在另一个文件之上播放另一个文件,而不是 muting/ducking 旧文件并替换为新文件?
class BroadcastDetailViewController: UIViewController {
var player = AVPlayer()
var playerItem: AVPlayerItem!
var broadcast:Broadcasts?
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBAction func playBroadcastButton(_ sender: Any) {
player.play()
setupAVAudioSession()
}
private func setupAVAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
debugPrint("AVAudioSession is Active and Category Playback is set")
UIApplication.shared.beginReceivingRemoteControlEvents()
setupCommandCenter()
} catch {
debugPrint("Error: \(error)")
}
}
private func setupCommandCenter() {
// Meta
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = broadcast?.title ?? "Radio Bass"
nowPlayingInfo[MPMediaItemPropertyArtist] = "Radio Bass"
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = "Radio Bass."
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playerItem.currentTime().seconds
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playerItem.asset.duration.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.play()
return .success
}
commandCenter.pauseCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.pause()
return .success
}
// Scrubber
commandCenter.changePlaybackPositionCommand.addTarget { event in
let seconds = (event as? MPChangePlaybackPositionCommandEvent)?.positionTime ?? 0
let time = CMTime(seconds: seconds, preferredTimescale: 1)
self.player.seek(to: time)
return .success
}
}
override func viewDidLoad() {
super.viewDidLoad()
let urlAudioString = broadcast?.audio
playerItem = AVPlayerItem(url: URL(string: urlAudioString!)!)
player = AVPlayer(playerItem: playerItem)
title = broadcast?.title
let urlImageString = broadcast?.image
let urlImage = URL(string: urlImageString!)
titleLabel.text = broadcast?.title
imageView.load(url: urlImage!)
}
}
Release/free 并在返回 table 视图控制器之前停止 AVPlayer
和 AVPlayerItem
avPlayer.pause()
avPlayer.cancelPendingPrerolls() // stops network requests
avPlayer.replaceCurrentItem(with: nil)
我正在构建一个 Swift 5 音乐应用程序,其中 table 视图加载并列出 JSON API 中的多个对象。单击条目后,导航器会调用 selected 项目的详细视图。
在下方,您可以看到我的详细视图控制器,名为 BroadcastDetailViewController
。如您所见,有一个 playBroadcastButton
将播放音频文件并设置 AVAudioSession
。
到目前为止一切顺利。但是在我实现了通过控制中心擦洗器 (commandCenter.changePlaybackPositionCommand.addTarget
) 擦洗音频文件并返回到我的 table 视图控制器和 select 另一个项目来播放它的音频文件的可能性之后, AVPlayer 将多个音频文件相互叠加并同时播放。这是我不想要的行为。在我实现控制按钮之前,整个音频文件替换过程运行良好。
我的问题是,为什么播放器突然在另一个文件之上播放另一个文件,而不是 muting/ducking 旧文件并替换为新文件?
class BroadcastDetailViewController: UIViewController {
var player = AVPlayer()
var playerItem: AVPlayerItem!
var broadcast:Broadcasts?
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBAction func playBroadcastButton(_ sender: Any) {
player.play()
setupAVAudioSession()
}
private func setupAVAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
debugPrint("AVAudioSession is Active and Category Playback is set")
UIApplication.shared.beginReceivingRemoteControlEvents()
setupCommandCenter()
} catch {
debugPrint("Error: \(error)")
}
}
private func setupCommandCenter() {
// Meta
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = broadcast?.title ?? "Radio Bass"
nowPlayingInfo[MPMediaItemPropertyArtist] = "Radio Bass"
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = "Radio Bass."
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playerItem.currentTime().seconds
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = playerItem.asset.duration.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.rate
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.play()
return .success
}
commandCenter.pauseCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.pause()
return .success
}
// Scrubber
commandCenter.changePlaybackPositionCommand.addTarget { event in
let seconds = (event as? MPChangePlaybackPositionCommandEvent)?.positionTime ?? 0
let time = CMTime(seconds: seconds, preferredTimescale: 1)
self.player.seek(to: time)
return .success
}
}
override func viewDidLoad() {
super.viewDidLoad()
let urlAudioString = broadcast?.audio
playerItem = AVPlayerItem(url: URL(string: urlAudioString!)!)
player = AVPlayer(playerItem: playerItem)
title = broadcast?.title
let urlImageString = broadcast?.image
let urlImage = URL(string: urlImageString!)
titleLabel.text = broadcast?.title
imageView.load(url: urlImage!)
}
}
Release/free 并在返回 table 视图控制器之前停止 AVPlayer
和 AVPlayerItem
avPlayer.pause()
avPlayer.cancelPendingPrerolls() // stops network requests
avPlayer.replaceCurrentItem(with: nil)