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!
I tried to build a project on Github for an easy check
I followed these steps:
Adding NSAppTransportSecurity to info.plist as in this answer to allow http
Trim the provided url to remove any spaces
let urlString = urlString.trimmingCharacters(in: .whitespacesAndNewlines)
Check if the string provides a valid link
guard let url = URL(string: urlString) else { return complete(.unvalidURL) }
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)
EDIT:
The part of AVAsset(url: url).isPlayable
might only check if the path ends with an appropriate extension as an example mp3, mp4.
I do not have access to check the actual code so I would only refer to the documentation