4

NOTE: Please read the title (and question) carefully before marking it as a duplicate. The question is about AVAudioPlayer not AVPlayer.


So according to docs for AVAudioPlayer

open func play() -> Bool /* sound is played asynchronously. */

I need to present user a popup exactly when the audio starts. This is not when we call play().

There is a delegate call for the case when player stops playing but not when it starts :(.

I couldn't find any means on how to know exactly when the audio starts. Is there any way to check it?

iur
  • 2,056
  • 2
  • 13
  • 30
  • if self.avPlayer?.currentItem?.status == AVPlayerItem.Status.readyToPlay { if (self.player?.currentItem?.isPlaybackLikelyToKeepUp) == true { // You can manage it here } } – Ahtazaz May 07 '19 at 10:40
  • 1
    @Mr.Ahtazaz please read the title carefully. It is not AVPlayer it is AVAudioPlayer. – iur May 07 '19 at 12:01
  • @Sh_Khan `AVPlayer` and `AVAudioPlayer` are two unrelated classes – mag_zbc May 07 '19 at 13:09
  • @iur You can start by trying to put observers on properties, for instance on `currentTime` – mag_zbc May 07 '19 at 13:12
  • @mag_zbc I also though about that. In docs there is a note on `playing` property `Important. Do not poll this property to determine when playback has completed, instead implement the specified delegate method.` so I am not sure if we can use it to check if the player started playing. – iur May 07 '19 at 13:28

1 Answers1

0

I'm facing the same issue, and just decide to make a new class based on AVPlayer:

import AVFoundation
import UIKit

 class AudioManager {

    private init() {}

    public static let shared = AudioManager()

    var player: AVPlayer?
    var item: AVPlayerItem?
    var layer: AVPlayerLayer?
    var currentUrl: URL?

    var pauseTime: CMTime?
    var endOfTrackObserver: Any?

    func startPlayContentOf(url: URL?) {

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.playerItemDidReachEnd(notification:)),
                                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
                                               object: self.player?.currentItem)

        guard let newAudioUrl = url else { return }
        let newAudioItem = AVPlayerItem(url: newAudioUrl)


        if let currentUrl = self.currentUrl, currentUrl == newAudioUrl {
            //same track
            if let playing = self.player?.isPlaying, playing == true  {
                self.pauseTime = self.player?.currentTime()
                self.pause()
            } else {
                self.player = AVPlayer(playerItem: newAudioItem)
                self.player?.volume = 3
                self.player?.seek(to: self.pauseTime ?? CMTime.zero)
                self.layer = AVPlayerLayer(player: self.player)
                self.layer?.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
                self.layer?.backgroundColor = UIColor.clear.cgColor
                guard let layer = self.layer else { return }
                UIApplication.shared.keyWindow?.rootViewController?.view.layer.insertSublayer(layer, at: 0)
                self.play()
            }
        } else {
            //new track
            self.pauseTime = nil
            self.pause()
            self.player = AVPlayer(playerItem: newAudioItem)
            self.player?.volume = 3
            self.layer = AVPlayerLayer(player: self.player)
            self.layer?.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
            self.layer?.backgroundColor = UIColor.clear.cgColor
            guard let layer = self.layer else { return }
            UIApplication.shared.keyWindow?.rootViewController?.view.layer.insertSublayer(layer, at: 0)
            self.play()
        }

        self.currentUrl = newAudioUrl
    }

    func playOrPause() {
        guard self.player != nil else { return }
        if self.player!.isPlaying {
            self.player!.pause()
        } else {
            self.player?.replaceCurrentItem(with: self.item)
            self.player!.play()
        }
    }

    func pause() {
        guard self.player != nil else { return }
        self.player!.pause()
    }

    func play() {
        guard self.player != nil else { return }
        self.player!.play()
    }

    @objc func playerItemDidReachEnd(notification: Notification) {
        self.pauseTime = nil
    }

}
stealthyninja
  • 10,343
  • 11
  • 51
  • 59