3

This is how in my code, playing from url, looks like:

private func play() {
    let streamUrl = ...        
    let playerItem = AVPlayerItem(url: streamURL)
    radioPlayer = AVPlayer(playerItem: playerItem)
    radioPlayer.volume = 1.0
    do {
         try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.mixWithOthers)
         try AVAudioSession.sharedInstance().setActive(true)
         UIApplication.shared.beginReceivingRemoteControlEvents()
     } catch {
         print("Error deactivating audio session.")
     }
     radioPlayer.play()
     startListeningForStreamFail()
     stopStartButton.setImage(#imageLiteral(resourceName: "pause_btn"), for: .normal)
}

Like the code snippet explains above, after calling the .play() function, I'm calling startListeningForStreamFail(), which registers the current viewcontroller to two types of notifications, on main thread.

private func startListeningForStreamFail() {
    DispatchQueue.main.async { [weak self] in
        NotificationCenter.default.addObserver(self as Any, selector: #selector(self?.playerItemFailedToPlay), name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: self?.radioPlayer?.currentItem)
        NotificationCenter.default.addObserver(self as Any, selector: #selector(self?.playerItemFailedToPlay), name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object: self?.radioPlayer?.currentItem)
    }
}

And the selector functions is this:

@objc private func playerItemFailedToPlay(notification: Notification) {
    print("playerItemFailedToPlay")
}

Because the stream right now works fine, I'm trying to test failure by addig some plus characters in it's url. But the playerItemFailedToPlay() functions does NOT get called, does NOT print anything.

Should this selector getting called, even if only the url was changed?

Any help would be appreciated. Thanks!

anitteb
  • 712
  • 10
  • 21
  • 1
    I built a testing project for you on [github](https://github.com/omiz/StreamTesterPlayer) try to test your link with it and please check the value of [NSAppTransportSecurity](https://stackoverflow.com/a/40299837/6689101) in your project – zombie Feb 19 '18 at 13:34
  • Thank you for the test project and for your patience! I've tested my url, if the url is correct it works fine, but with the "fake" url does not get any error. I'm wondering if I get the same error code if 1. the url is valid (but stream doesn't work) and if 2. the url isn't valid. – anitteb Feb 19 '18 at 14:05
  • 1
    I added a small trick to solve a fake url. please let me know if that works for you – zombie Feb 19 '18 at 14:13
  • In the `setup()` function if the url `!asset.isPlayable` I've changed the completion value from `nil` to `.unvalidURL`. And now it works. I've understood your logic, thank you very much! – anitteb Feb 19 '18 at 14:37

1 Answers1

7

I tried to build a project on Github for an easy check

I followed these steps:

  1. Adding NSAppTransportSecurity to info.plist as in this answer to allow http

  2. Trim the provided url to remove any spaces

    let urlString = urlString.trimmingCharacters(in: .whitespacesAndNewlines)

  3. Check if the string provides a valid link

    guard let url = URL(string: urlString) else { return complete(.unvalidURL) }

  4. Check if the link is playable

    AVAsset(url: url).isPlayable

If any of the previous steps was not successful then it means the url is not valid

I also added an observers for the errors after starting a playable link

NotificationCenter.default.addObserver(self, selector: #selector(itemFailedToPlayToEndTime(_:)), name: .AVPlayerItemFailedToPlayToEndTime, object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(itemNewErrorLogEntry(_:)), name: .AVPlayerItemNewErrorLogEntry, object: nil)

NotificationCenter.default.addObserver(self, selector: #selector(itemPlaybackStalled(_:)), name: .AVPlayerItemPlaybackStalled, object: nil)
zombie
  • 4,774
  • 3
  • 23
  • 52