It’s easy to play
Generally divided into two processes, ready to play, and play
Ready to play, including ready to play resources, player initialization and player ready
Which is ready to play resources
var currentAudioPath:URL!
currentAudio = readSongNameFromPlist(currentAudioIndex)
if let path = Bundle.main.path(forResource: currentAudio, ofType: "mp3"){
currentAudioPath = URL(fileURLWithPath: path)
}
else{
alertSongExsit()
}
Copy the code
Player initialization and player ready
var audioPlayer:AVAudioPlayer! audioPlayer = try? AVAudioPlayer(contentsOf: currentAudioPath) audioPlayer.delegate = self audioLength = audioPlayer.duration playerProgressSlider.maximumValue = CFloat (audioPlayer. Duration) playerProgressSlider. MinimumValue = 0.0 playerProgressSlider. Value = 0.0 audioPlayer.prepareToPlay()Copy the code
play
Audioplayer.play (), one line of code
First, how do I make the progress bar?
A normal progress bar does two things,
As the playback progresses, the slider of the progress bar will keep moving forward, with a music playing match to the progress of the progress bar
The slider of the progress bar can be dragged to control where the current play can be played, for example, can be skipped
Play music, progress bar slider also move, progress is matched
Before each playback, set the progress bar.
MaximumValue is the amount of time it takes to finish a song
MinimumValue the minimumValue, that is, it is not playing, is 0
When value starts, it just doesn’t play, it’s 0
PlayerProgressSlider. MaximumValue = CFloat (audioPlayer. Duration) playerProgressSlider. MinimumValue = 0.0 PlayerProgressSlider. Value = 0.0Copy the code
To keep the progress bar slider moving forward, you need a timer
func startTimer() {ifTimer == nil {timer = timer.scheduledTimer (timeInterval: 1.0, target: self, selector:#selector(PlayerViewController.update(_:)), userInfo: nil,repeats: true)Timer.fire ()}} // Every second, to get the current playback time of the player, refresh the status of the progress bar playerProgressSlider @objc func update(_ timer: timer){if! audioPlayer.isPlaying{return
}
let time = calculateTimeFromNSTimeInterval(audioPlayer.currentTime)
playerProgressSlider.value = CFloat(audioPlayer.currentTime)
}
Copy the code
Drag the slider of the progress bar to adjust the position of the playback
Because the range of the scrollbar matches the length of the player
So set currentTime to the currentTime of the player
Pause first, then set currentTime of the player, after a short interval
The transition is smoother and the experience is slightly better
@IBAction func changeAudioLocationSlider(_ sender : UISlider) { audioPlayer.pause() audioPlayer.currentTime = TimeInterval(sender.value) DispatchQueue. Main. AsyncAfter (deadline: now () + 0.5) {self. The audioPlayer. The play ()}}Copy the code
Do fast forward and fast back, the same idea, change the current time of the playeraudioPlayer.currentTime
Second, out of order play and loop play, how to do?
Use out-of-order play and loop play two buttons, for the next song, and after the song
They do not affect the current song playback
So these two buttons click, they change the UI, they change the state, and when the current song is finished, it works
Or it’s not playing right now, and the next time it’s playing, the first song is done and it works
@IBAction func shuffleButtonTapped(_ sender: UIButton) {
shuffleArray.removeAll()
if sender.isSelected{
sender.isSelected = false
shuffleState = false
} else {
sender.isSelected = true
shuffleState = true
}
}
@IBAction func repeatButtonTapped(_ sender: UIButton) {
if sender.isSelected == true {
sender.isSelected = false
repeatState = false
} else {
sender.isSelected = true
repeatState = true}}Copy the code
Out-of-order and circulation, done in AVAudioPlayerDelegate play play a role in the callback method func audioPlayerDidFinishPlaying (_ player: AVAudioPlayer, successfully flag: Bool){
Single loop effect
So instead of clicking out of order, just clicking on loop,
if shuffleState == false && repeatState == true{//repeat same song prepareAudio() playAudio()Copy the code
Out of order, no circulation effect
I didn’t hit loop, I just hit Out of order,
If it’s out of order, you have to pick a random number,
Do not cycle, it is necessary to remove repetition, here is to play the song list again, it is over
Var shuffleArray = [Int]()if shuffleState == true && repeatState == false{// Add shufflearray. append(currentAudioIndex) // Add an end condition, not less than the list of songsif shuffleArray.count >= audioList.count {
playButton.setImage( UIImage(named: "play"), for: UIControl.State())
returnVar newIndex = 0 var newIndex = 0 var newIndex = 0 var newIndex = 0false
while newIndex == false {
randomIndex = Int(arc4random_uniform(UInt32(audioList.count)))
if shuffleArray.contains(randomIndex) {
newIndex = false
}else{
newIndex = trueCurrentAudioIndex = randomIndex // prepareAudio() playAudio()Copy the code
Out-of-order loop effect
That’s loop and out of order
If it’s out of order, you have to pick a random number,
Out of order loop, here is to play the list out of order once, and then again
Var shuffleArray = [Int]()if shuffleState == true && repeatState == true{//shuffle song toil // add shufflearray. append(currentAudioIndex) // repeat conditions, so that all the songs have been played before, and so onifShufflearray.count >= audiolist.count {shufflearray.removeall ()} Var randomIndex = 0 var newIndex =false
while newIndex == false {
randomIndex = Int(arc4random_uniform(UInt32(audioList.count)))
if shuffleArray.contains(randomIndex) {
newIndex = false
}else{
newIndex = trueCurrentAudioIndex = randomIndex // prepareAudio() playAudio()}Copy the code
Third, lock screen play and switch to another application play
It’s actually playing in the background
Set the background mode to keep the session alive
do {
//keep alive audio at background
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
} catch _ { }
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ { }
Copy the code
Fourth, remote control events for the player
At the bottom of the screen pops the player control events
Controls events for the player after the lock screen
The first step is to receive remote control events
//LockScreen Media control registry
if UIApplication.shared.responds(to: #selector(UIApplication.beginReceivingRemoteControlEvents)){
UIApplication.shared.beginReceivingRemoteControlEvents()
UIApplication.shared.beginBackgroundTask(expirationHandler: { () -> Void in})}Copy the code
Synchronize the play information to the lock screen player with the bottom popup window of the player
When it’s playing, synchronize it to the lock screen and the popup at the bottom,
// This shows media info on lock screen - used currently and perform controls
func showMediaInfo() {let artistName = readArtistNameFromPlist(currentAudioIndex)
let songName = readSongNameFromPlist(currentAudioIndex)
MPNowPlayingInfoCenter.default().nowPlayingInfo = [MPMediaItemPropertyArtist : artistName, MPMediaItemPropertyTitle : songName]
}
Copy the code
Finally, rewritefunc remoteControlReceived
methods
When locking the screen, you can pause and play the player, click on the previous song, and next song
And when I pull up the bottom popover
override func remoteControlReceived(with event: UIEvent?) {
ifevent! .type == UIEvent.EventType.remoteControl{ switch event! .subtype{case UIEventSubtype.remoteControlPlay:
play(self)
case UIEventSubtype.remoteControlPause:
play(self)
case UIEventSubtype.remoteControlNextTrack:
next(self)
case UIEventSubtype.remoteControlPreviousTrack:
previous(self)
default:
print("There is an issue with the control")}}}Copy the code
Fifth, how to play a variety of files, MP3, M4A?
Instantiate AVAudioPlayer via binary data
var player: AVAudioPlayer!
var tempPath: String?
if let mpPath = Bundle.main.path(forResource: str, ofType: "mp3"){
tempPath = mpPath
}
if let maPath = Bundle.main.path(forResource: str, ofType: "m4a"){
tempPath = maPath
}
guard let path = tempPath, let playerTmp = try? AVAudioPlayer(data: Data(contentsOf: URL(fileURLWithPath: path))) else{
return
}
self.player = playerTmp
Copy the code
Code of this article:Github.com/coyingcat/m…
This article is based on Bpolat /Music-Player