0

I read through many similar questions on stackoverflow, and while they helped, I still can't get the next song to play automatically when the one that's currently playing finishes. Since I start the array of songs at position 0, when I increment this position variable, shouldn't all the songs play, one after another, until I get to the last song in the array? Currently, after the first song finishes playing, the second song plays, the rest do not. So my code can only play two songs at a time, one after the other. I set up the songs initially inside the configureUI() method and I try to increment the songs in the AVAudioplayer delegate method at the bottom. I appreciate any insight.

//
//  PLayerViewController.swift
//  Maanso
//
//

import UIKit
import AVFoundation

class PLayerViewController: UIViewController, AVAudioPlayerDelegate {
    @IBOutlet var holder: UIView!
    var Git = UILabel()
    var gabayArray = [Gabays]()
    var currentIndex = 0
    var position: Int = 0
    
    var player: AVAudioPlayer?
    
    //user interface elements
    var coverImageView: UIImageView!
    var gabayName: UILabel!
    var gabyaaName: UILabel!
    
    //buttons
    var playPauseButton: UIButton!
    var backButton: UIButton!
    var forwardButton: UIButton!

    
    var timer: Timer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configure()
        player!.delegate = self
        
//        configureUI()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        if let player = player {
//            player.play()
            player.prepareToPlay()
        }
    }
    
    
    override func viewDidLayoutSubviews() {
        if holder.subviews.count == 0 {
            configure()
        }
    }

    
    func configure() {
        //set up player
        
        let gabay = gabayArray[position]
//        let urlString = Bundle.main.path(forResource: gabay.gabayName, ofType: "mp3")
        let urlString = Bundle.main.path(forResource: gabay.gabayName, ofType: "mp3")

        
        do {
            try AVAudioSession.sharedInstance().setMode(.default)
            try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
            
            guard let urlString = urlString else{return}
            
            player = try AVAudioPlayer(contentsOf: URL(string: urlString)!)
            guard let player = player else{return}
            player.volume = 0.5
            player.play()
            
        }
        
        catch{
            print("error is: \(error.localizedDescription)")
        }
       configureUI()

    }
    
    
    //MARK: - actions
    @objc func volumeSliderChanged(_ slider: UISlider) {
        let value = slider.value
        //adjust player volume
        guard let player = player else{return}
        player.volume = value
       
    }
    
    
    @objc func playPauseButtonTapped(_ slider: UISlider) {
       
       
        
        guard let player = player else{return}
        
        if player.isPlaying {
            player.stop()
            playPauseButton.setBackgroundImage(UIImage(systemName: "play.fill"), for: .normal)
           
        }else{
            player.play()
            playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)

           
        }
      
        
        
    }
    
        
            
        @objc func backButtonTapped() {
        if position > 0
        {
            position = position - 1
            player!.stop()
            for subview in holder.subviews {
                subview.removeFromSuperview()
            }
            configure()
//            configureUI()
        }
    }
    
    
    @objc func forwardButtonTapped() {
        if position < gabayArray.count - 1{
            position = position + 1
            player!.stop()
            
            for subview in holder.subviews {
                subview.removeFromSuperview()
            }
            configure()
//            configureUI()
        }
    }
    
    @objc func seekSliderChanged(_ slider: UISlider) {
        let slider = slider
//        let currentTime = player!.currentTime
        let duration = player!.duration
        slider.maximumValue = Float(duration)
        let time = duration/duration
        //seeking through current gabay
        player!.currentTime = TimeInterval(slider.value)
       
//        player!.play()
        Timer.scheduledTimer(withTimeInterval: Double(time), repeats: true, block: {
            _ in
            slider.value = Float(self.player!.currentTime)
            //TRYING TO MAKE THE SLIDER BE IN SYNC WITH song
           
            
        })
        
      
    }
    
    
    
  public  func configureUI() {
        
        //set up user interface
        let gabay = gabayArray[position]

        //set up imagecoverview
        coverImageView = UIImageView()
        coverImageView.contentMode = .scaleAspectFill
        coverImageView.image = UIImage(named: gabay.imageName)
        coverImageView.translatesAutoresizingMaskIntoConstraints = false
        holder.addSubview(coverImageView)

        
        //set up the two labels
        gabayName = UILabel()
        gabayName.textAlignment = .center
        gabayName.numberOfLines = 0
        gabayName.translatesAutoresizingMaskIntoConstraints = false
        gabayName.text = gabay.gabayName
        gabayName.font = UIFont(name: "helvetica", size: 20)
        holder.addSubview(gabayName)
        
        gabyaaName = UILabel()
        gabyaaName.translatesAutoresizingMaskIntoConstraints = false
        gabyaaName.text = gabay.gabyaaName
        gabyaaName.font = UIFont(name: "helvetica", size: 18)
        gabyaaName.textAlignment = .center
        gabyaaName.numberOfLines = 0
        holder.addSubview(gabyaaName)


        
        
        //set up sliders.
        let volumeSlider = UISlider()
        volumeSlider.value = 0.5
        volumeSlider.translatesAutoresizingMaskIntoConstraints = false
        volumeSlider.addTarget(self, action: #selector(volumeSliderChanged), for: .valueChanged)
        volumeSlider.layer.cornerRadius = 8
        volumeSlider.isUserInteractionEnabled = true
        holder.addSubview(volumeSlider)
      
      //seek through sider
      let seekSlider = UISlider()
//      seekSlider.isContinuous = true
      seekSlider.minimumValue = 0
//      seekSlider.maximumValue = Float(player!.duration)
      seekSlider.isUserInteractionEnabled = true
      seekSlider.translatesAutoresizingMaskIntoConstraints = false
//      seekSlider.setThumbImage(UIImage(systemName: "thumbSmall"), for: .normal)
      seekSlider.setThumbImage(UIImage(named: "thumb"), for: .normal)
      seekSlider.addTarget(self, action: #selector(seekSliderChanged), for: .valueChanged)
      holder.addSubview(seekSlider)
        
        
        
        //set up buttons, play button
        playPauseButton = UIButton()
        playPauseButton.tintColor = .black
        playPauseButton.setBackgroundImage(UIImage(systemName: "pause.fill"), for: .normal)
        playPauseButton.translatesAutoresizingMaskIntoConstraints = false
        playPauseButton.addTarget(self, action: #selector(playPauseButtonTapped), for: .touchUpInside)
        holder.addSubview(playPauseButton)
        
        //back button
        backButton = UIButton()
        backButton.tintColor = .black
        backButton.setBackgroundImage(UIImage(systemName: "backward.fill"), for: .normal)
        backButton.translatesAutoresizingMaskIntoConstraints = false
        backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
        holder.addSubview(backButton)
        
        //forward button
         forwardButton = UIButton()
       
        forwardButton.tintColor = .black
        forwardButton.setBackgroundImage(UIImage(systemName: "forward.fill"), for: .normal)
        forwardButton.translatesAutoresizingMaskIntoConstraints = false
        forwardButton.addTarget(self, action: #selector(forwardButtonTapped), for: .touchUpInside)
        holder.addSubview(forwardButton)
      
      //volume buttons
   
      let rightVolButton = UIButton()
      rightVolButton.translatesAutoresizingMaskIntoConstraints = false
      rightVolButton.setBackgroundImage(UIImage(systemName: "volume.3.fill"), for: .normal)
      holder.addSubview(rightVolButton)

        
        

        //set up constraints
        NSLayoutConstraint.activate([
            coverImageView.topAnchor.constraint(equalTo: holder.layoutMarginsGuide.topAnchor, constant: 80),
            coverImageView.leadingAnchor.constraint(equalTo: holder.layoutMarginsGuide.leadingAnchor, constant: 0),
            coverImageView.trailingAnchor.constraint(equalTo: holder.layoutMarginsGuide.trailingAnchor, constant: 0),


            
            gabayName.topAnchor.constraint(equalTo: coverImageView.bottomAnchor, constant: 100),
            gabayName.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
          

            gabyaaName.topAnchor.constraint(equalTo: gabayName.bottomAnchor, constant: 15),
            gabyaaName.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
            
            
            //seek slider
            seekSlider.topAnchor.constraint(equalTo: gabyaaName.topAnchor, constant: 30),
            seekSlider.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
            seekSlider.widthAnchor.constraint(equalTo: holder.widthAnchor, multiplier: 0.8),
            

           
            
            //buttons
            playPauseButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
            playPauseButton.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
            playPauseButton.widthAnchor.constraint(equalToConstant: 70),
            playPauseButton.heightAnchor.constraint(equalToConstant: 70),

            
            backButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
            backButton.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 20),
            backButton.widthAnchor.constraint(equalToConstant: 70),
            backButton.heightAnchor.constraint(equalToConstant: 70),


            
            forwardButton.topAnchor.constraint(equalTo: seekSlider.bottomAnchor, constant: 25),
            forwardButton.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: -20),
            forwardButton.widthAnchor.constraint(equalToConstant: 70),
            forwardButton.heightAnchor.constraint(equalToConstant: 70),

            
            
            //volume slider
            volumeSlider.topAnchor.constraint(equalTo: playPauseButton.bottomAnchor, constant: 30),
            volumeSlider.centerXAnchor.constraint(equalTo: holder.centerXAnchor),
            volumeSlider.widthAnchor.constraint(equalTo: holder.widthAnchor, multiplier: 0.8),

            
           
            
            rightVolButton.topAnchor.constraint(equalTo: playPauseButton.bottomAnchor, constant: 35),
            rightVolButton.trailingAnchor.constraint(equalTo: holder.layoutMarginsGuide.trailingAnchor, constant: 0),

            
            
            
            

                
        ])
        
    
    }
    
    
  //MARK: - AVAudioplayer delegate
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        if flag, position < gabayArray.count - 1 {
            position = position + 1

            for subview in holder.subviews{
                subview.removeFromSuperview()
            }
            configure()

        }

        }
      
       
    
    
  
   
    override func viewWillDisappear(_ animated: Bool) {
        player?.stop()
    }
    
    
    

   
        
        }

    
  
   


1 Answer 1

0

I was able to solve the problem by simply setting the player's delegate after loading the music file initially. For anyone struggling with this, this is what I did.

  1. Use the AVAudioPlayer delegate method to keep track of when the song that's currently playing ends.
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {}
  1. Inside that method, check to see if the current song that's playing is not the last song in the array, and if it is not, increment the increment variable. For me, it was position which I had set to 0 initially.

  2. Call the methods that configures the audio initially. For me it as the configure() method. Don't forget to set the delegate of the audio in this method after loading the audio file.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.