首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MPRemoteCommandCenter错误:曲目同时播放多次

MPRemoteCommandCenter错误:曲目同时播放多次
EN

Stack Overflow用户
提问于 2021-06-01 16:10:00
回答 1查看 42关注 0票数 0

我有TableViewControllerAudioPlayerViewController。我在使用MPRemoteCommandCenter时遇到了问题。例如:在TableViewController中,我点击手机,然后进入AudioPlayerViewController,下一步我锁定设备,然后用MPRemoteCommandCenter控制我的音乐--一切正常。但是,如果我进一步解锁设备,返回到TableViewController,再次转到AudioPlayerViewController锁定设备,并按下播放/暂停按钮,我的音乐将同时播放两次。如果我重复这个动作,我的音乐将同时播放三次。等等..。如何修复它?

代码:

代码语言:javascript
复制
import UIKit
import AVFoundation
import MediaPlayer

class ViewController: UIViewController, AVAudioPlayerDelegate, UIAlertViewDelegate {
    
    var audioPlayer: AVAudioPlayer!
    let musicOperation = OperationQueue()
    var timer: Timer?
    
    @IBOutlet weak var playButton: UIButton!
    @IBOutlet var timeElapsed: UILabel!
    @IBOutlet var timeDuration: UILabel!
    @IBOutlet weak var logo: UIImageView!
    @IBOutlet weak var slider: UISlider!
    @IBOutlet weak var volumeView: UIView!
    
    var index = 0
    var buttonIndex = 0
    
    var endOfChapterSleepTimer = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Table View Index
        buttonIndex = masterIndex
        
        musicOperation.maxConcurrentOperationCount = 1
        
        try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        
        UserDefaults.standard.set(index, forKey: "index")
        
        if index > 0 {

            let fileManager = FileManager.default
            let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
            
            if let documentDirectoryURL: NSURL = urls.first as NSURL? {
                
                let soundURL = documentDirectoryURL.appendingPathComponent("/\(masterIndex)/\(index).mp3")
                
                UserDefaults.standard.set(index, forKey: "\(masterIndex)")
                
                do {
                    
                    audioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
                    audioPlayer.delegate = self
                    audioPlayer.prepareToPlay()
                    play(sender:AnyObject.self as AnyObject)
                    restorePlayerCurrentTime()
                    
                    setupMediaPlayerNotificationView()
                    lockScreen()
                    
                } catch {
                    
                }
            }
            
        } else {
            
            let url = Bundle.main.url(forResource: "\(masterIndex)0", withExtension: "m4a")!
            
            do {
                
                audioPlayer = try AVAudioPlayer(contentsOf: url)
                audioPlayer.delegate = self
                audioPlayer.prepareToPlay()
                play(sender:AnyObject.self as AnyObject)
                
                setupMediaPlayerNotificationView()
                lockScreen()
                
            } catch {
                
            }
        }
        
    }
    
    // MARK: - Audio player controller
    
    @IBAction func play(sender: AnyObject) {
        if !audioPlayer.isPlaying{
            audioPlayer.play()
            slider.maximumValue = Float(audioPlayer.duration)
            timer = Timer(timeInterval: 0.1, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)
            RunLoop.main.add(timer!, forMode: .commonModes)
            restorePlayerCurrentTime()
            playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
        } else {
            audioPlayer.pause()
            playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
            timer?.invalidate()
        }
    }
    
    @IBAction func fastForward(sender: AnyObject) {
        var time: TimeInterval = audioPlayer.currentTime
        time += 15.0 // Go Forward by 15 Seconds
        if time > audioPlayer.duration {
            audioPlayerDidFinishPlaying(audioPlayer, successfully: true)
        } else {
            audioPlayer.currentTime = time
            updateTime()
        }
    }
    
    @IBAction func fastBackward(sender: AnyObject) {
        var time: TimeInterval = audioPlayer.currentTime
        time -= 15.0 // Go Back by 15 Seconds
        if time < 0 {
            audioPlayer.currentTime = 0
            updateTime()
        } else {
            audioPlayer.currentTime = time
            updateTime()
        }
    }
    
    // MARK: - Audio player time
    
    private func restorePlayerCurrentTime() {
        let currentTimeFromUserDefaults : Double? = UserDefaults.standard.value(forKey: "currentTime\(masterIndex)\(index)") as! Double?
        if let currentTimeFromUserDefaultsValue = currentTimeFromUserDefaults {
            audioPlayer.currentTime = currentTimeFromUserDefaultsValue
            slider.value = Float.init(audioPlayer.currentTime)
        }
    }
    
    @objc func updateTime() {
        let currentTime = Int(audioPlayer.currentTime)
        let minutes = currentTime/60
        let seconds = currentTime - minutes * 60
        
        let durationTime = Int(audioPlayer.duration) - Int(audioPlayer.currentTime)
        let minutes1 = durationTime/60
        let seconds1 = durationTime - minutes1 * 60
        
        timeElapsed.text = NSString(format: "%02d:%02d", minutes,seconds) as String
        timeDuration.text = NSString(format: "-%02d:%02d", minutes1,seconds1) as String
        
        UserDefaults.standard.set(currentTime, forKey: "currentTime\(masterIndex)\(index)")
        UserDefaults.standard.set(durationTime, forKey: "durationTime\(masterIndex)\(index)")
        
        slider.value = Float.init(audioPlayer.currentTime)
    }
    
    func audioPlayerDidFinishPlaying(_ audioPlayer: AVAudioPlayer, successfully flag: Bool) {
        
        playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
        
        let currentTime = 0
        let durationTime = 0.1
        UserDefaults.standard.set(currentTime, forKey: "currentTime\(masterIndex)\(index)")
        UserDefaults.standard.set(durationTime, forKey: "durationTime\(masterIndex)\(index)")
        slider.value = Float.init(audioPlayer.currentTime)
        timer?.invalidate()
        
        let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        let documentDirectoryPath:String = path[0]
        let fileManager = FileManager()
        let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/\(masterIndex)/\(index+1).mp3"))
        
        if fileManager.fileExists(atPath: destinationURLForFile.path){
            
        
        index = index + 1
        viewDidLoad()
            
        } else {
            
        }
    }
    
    // MARK: - Audio player lock screen
    
    func lockScreen() {
        
        var albumArtwork : MPMediaItemArtwork!
        let image:UIImage = UIImage(named: "infoImage")!
        
        albumArtwork = MPMediaItemArtwork.init(boundsSize: image.size, requestHandler: { (size) -> UIImage in
            return image
        })
        
        let infotitle = "title"
        
        MPNowPlayingInfoCenter.default().nowPlayingInfo = [
            MPMediaItemPropertyArtist : "",
            MPMediaItemPropertyTitle : infotitle,
            MPMediaItemPropertyArtwork : albumArtwork,
            MPMediaItemPropertyAlbumTitle : "",
            MPNowPlayingInfoPropertyElapsedPlaybackTime : Int(audioPlayer.currentTime),
            MPMediaItemPropertyPlaybackDuration: Int(audioPlayer.duration)]
        
    }
    
    func setupMediaPlayerNotificationView()  {
        
        let commandCenter = MPRemoteCommandCenter.shared()
        
        commandCenter.playCommand.addTarget { event in
            self.audioPlayer.play()
            self.lockScreen()
            self.playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
            print("play")
            return .success
        }
        
        commandCenter.pauseCommand.addTarget { event in
            self.audioPlayer.pause()
            self.lockScreen()
            self.playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
            print("pause")
            return .success
        }
        
        commandCenter.skipBackwardCommand.preferredIntervals = [15]
        commandCenter.skipBackwardCommand.addTarget { event in
            self.fastBackward(sender: self)
            self.lockScreen()
            print("fastBackward")
            return .success
        }
        
        commandCenter.skipForwardCommand.preferredIntervals = [15]
        commandCenter.skipForwardCommand.addTarget { event in
            self.fastForward(sender: self)
            self.lockScreen()
            print("fastForward")
            return .success
        }
        
        commandCenter.changePlaybackPositionCommand.addTarget(self, action: #selector(self.changedThumbSlider(_:)))
        
    @objc func changedThumbSlider(_ event: MPChangePlaybackPositionCommandEvent) -> MPRemoteCommandHandlerStatus {
        let time = event.positionTime
        audioPlayer.currentTime = TimeInterval(time)
        self.lockScreen()
        return .success
    }
    
    // MARK: - Audio player slider
    
    @IBAction func slide(_ slider: UISlider) {
        musicOperation.cancelAllOperations()
        let operation = BlockOperation()
        audioPlayer.currentTime = TimeInterval(slider.value)
        self.lockScreen()
        musicOperation.addOperation(operation)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        audioPlayer.pause()
        timer?.invalidate()
        musicOperation.cancelAllOperations()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        UIView.setAnimationsEnabled(true)
        
        // Navigation Bar
        
        self.navigationController?.navigationBar.prefersLargeTitles = true
        self.navigationItem.largeTitleDisplayMode = .always
        self.navigationController?.navigationBar.shadowImage = UIImage()
        self.navigationController?.navigationBar.barTintColor = UIColor(red: 55/255, green: 60/255, blue: 65/255, alpha: 1.0)
        self.navigationController?.navigationBar.isTranslucent = true
        self.navigationController?.navigationBar.tintColor = .white
        self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-01 16:38:34

发生的情况是,每次您转到AudioPlayerViewController时都会启用MPRemoteCommandCenter,但是当您返回到TableViewController时,您不会调用removeTarget。这是你的问题。

在viewWillDisappear to removeTarget中调用类似下面的内容

代码语言:javascript
复制
func setupMediaPlayerNotificationView(_ enable: Bool)  {

let commandCenter = MPRemoteCommandCenter.shared()

if enable {
    commandCenter.playCommand.addTarget(self, action: #selector(self.lockScreenPlay(_:)))
    commandCenter.pauseCommand.addTarget(self, action: #selector(self.lockScreenPlay(_:)))
    commandCenter.nextTrackCommand.addTarget(self, action: #selector(self.lockScreenNextTrack(_:)))
    commandCenter.previousTrackCommand.addTarget(self, action: #selector(self.lockScreenPreviousTrack(_:)))
} else {
    commandCenter.playCommand.removeTarget(self, action: #selector(self.lockScreenPlay(_:)))
    commandCenter.pauseCommand.removeTarget(self, action: #selector(self.lockScreenPlay(_:)))
    commandCenter.nextTrackCommand.removeTarget(self, action: #selector(self.lockScreenNextTrack(_:)))
    commandCenter.previousTrackCommand.removeTarget(self, action: #selector(self.lockScreenPreviousTrack(_:)))
    }
}

后续问题示例:

代码语言:javascript
复制
@objc func lockScreenPlay(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
    self.playButton(AnyObject.self)
    return .success
}

@objc func lockScreenNextTrack(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
        self.playerDidFinishPlaying()
    return .success
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67785052

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档