Search code examples
iosswiftswift3avaudioplayeraudio-player

How to track when song is finished AVAudioPlayer


I want to track when playing song is finished. I tried different solutions from the web but they could not solve my problem. I implemented audioPlayerDidFinishPlaying method but it is not working. How can I understand if playing song is finished?

I am playing songs with playSound function

playSound func:

func playSound(name: String ) {
    guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
        print("url not found")
        return
    }

    do {
        /// this codes for making this app ready to takeover the device audio
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        /// change fileTypeHint according to the type of your audio file (you can omit this)
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
        // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
        player!.play()
    } catch let error as NSError {
        print("error: \(error.localizedDescription)")
    }
}

audioPlayerDidFinishPlaying func:

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    print("finished")//It is not working, not printing "finished"
}

How can I solve my problem? How to track when playing song is finished

EDIT: I am adding whole code.

//
//  ViewController.swift

import UIKit
import SwiftVideoBackground
import AudioToolbox
import AVFoundation


class ViewController: UIViewController,AVAudioPlayerDelegate {

    var player: AVAudioPlayer?

    @IBOutlet weak var backgroundVideo: BackgroundVideo!

    @IBOutlet weak var initialLabel: UILabel!

    @IBOutlet weak var statementLabel: UILabel!


    var mp3: [String] = ["turk_milleti_demokrattir","xyz"]
    var fav: [String] = ["0","0"]
    var name: [String] = ["Türk milleti demokrattır","xy"]


    var toggleState = 1


    @IBOutlet weak var playB: UIButton!

    var counter = 0

    var duration = 0.1


    override func viewDidLoad() {
        super.viewDidLoad()

        player?.delegate = self

        playB.setImage(UIImage(named: "playbtn.png"), for: .normal)

        statementLabel.text = name[counter]

       backgroundVideo.createBackgroundVideo(name: "abc", type: "mp4")





    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    @IBAction func likeButton(_ sender: Any) {


        fav[counter] = "1"
        print(fav[0...1])


    }

    @IBAction func playButton(_ sender: Any) {
        let name = mp3[counter]
        playSound(name: name)


        let playBtn = sender as! UIButton
        if toggleState == 1 {
            player?.play()
            toggleState = 2
            playBtn.setImage(UIImage(named: "pausebtn.png"), for: .normal)
        } else {
            player?.pause()
            toggleState = 1
            playBtn.setImage(UIImage(named:"playbtn.png"),for: .normal)
        }  

    }


    @IBAction func nextButton(_ sender: Any) {

        counter = counter + 1

        if counter == mp3.count {
            counter = 0
        }

        toggleState = 2
        playB.setImage(UIImage(named: "pausebtn.png"), for: .normal)

        playSound(name: mp3[counter])

        statementLabel.text = name[counter]

    }





    func playSound(name: String ) {
        guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
            print("url not found")
            return
        }

        do {
            /// this codes for making this app ready to takeover the device audio
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try AVAudioSession.sharedInstance().setActive(true)

            /// change fileTypeHint according to the type of your audio file (you can omit this)
            player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)



            // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
            player!.play()
        } catch let error as NSError {
            print("error: \(error.localizedDescription)")
        }
    }

    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        print("finished")//It is not working, not printing "finished"
    }


}

Solution

  • I solved my problem with help of Leo Dabus. I changed my edited code. I moved player?.delegate = self to playSound func. Finally, it is working.

    playSound & audioPlayerDidFinishPlaying function:

      func playSound(name: String ) {
            guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
                print("url not found")
                return
            }
    
            do {
                /// this codes for making this app ready to takeover the device audio
                try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
                try AVAudioSession.sharedInstance().setActive(true)
    
                /// change fileTypeHint according to the type of your audio file (you can omit this)
                player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
    
                player?.delegate = self
    
                // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
                player!.play()
            } catch let error as NSError {
                print("error: \(error.localizedDescription)")
            }
        }
    
        func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
            print("finished")//It is working now! printed "finished"!
        }
    

    Do not forget to add AVAudioPlayerDelegate to ViewController!

    class ViewController: UIViewController,AVAudioPlayerDelegate {