An online mp3 AVPlayerItem that failed to play will never play again - ios

I am having trouble playing online mp3 files as AVPlayerItems which have previously failed to play due to data connection issues.
For example:
I try play online mp3 file "FILE_A" with poor data connection and the associated AVPlayerItem fails to play. The AVPlayerItem will then not load and my AVPlayer will stay paused (which is fine for now).
Let's say that after a period of time I gain better data connection and play a different online mp3 file "FILE_B" as an AVPlayerItem. The AVPlayer plays this AVPlayerItem with no issues.
I then try play the failed file "FILE_A" on good data connection. The AVPlayerItem for "FILE_A" will always refuse to play. I can even close/kill the app and try again and "FILE_A" will not play. The only work around is to do a fresh re-install of the app.
I have 3 questions:
Why does a failed AVPlayerItem never become playable, is there a AVPlayerItem cache in the AVPlayer that always tries to play the failed item?
Is there a way to refresh an unplayable AVPlayerItem to make it play again?
What is the best way to deinitialize an AVPLayer? Currently I am using self.player = nil to deinitialize the player in the deint of my view controller or when a user logs out of their account in the app.
This is how I set up the AVPlayer:
self.player = AVPlayer()
self.player?.actionAtItemEnd = .pause
self.player?.automaticallyWaitsToMinimizeStalling = false
self.player?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
This is how I set up an AVPlayerItem and set it as the AVPlayer's currentItem:
let url = URL(string: onlineAudioFileUrl)
currentPlayerItem = AVPlayerItem(url: url)
player?.replaceCurrentItem(with: currentPlayerItem)
The onlineAudioFileUrl above is String url representing the url of an online mp3 file stored on a server. It has the form:
https://ourserver.com/audio_file_name.mp3?Expires=NUMERIC_EXPIRE_TIME&Key-Pair-Id=KEY_PAIR_ID_STRING&Signature=VERY_LONG_SIGNATURE_STRING

Related

How to use AVMutableAudioMix with AVPlayer audio that is streaming in from the net (NOT local files)?

This question is about AVPlayer (not AVAudioPlayer).
Say you have a couple of videos, which you are playing at the same time:
py1 = AVPlayer(url: URL(string: "https:// a.. .mp4")!)
py1 = AVPlayer(url: URL(string: "https:// b.. .mp4")!)
Say they're both playing. (Imagine them both playing on differnt parts of the screen.)
In short: how can we hear both?
You can hear one of the other by setting the .volume to zero on one of them,
but how to get a mix of both audios?
It seems impossible / very challenging to get AVMutableAudioMix to work on AVPlayer which are playing a remote URL.
Has anyone cracked this?

Free hosting video platform compatible with AVPlayer support

I am trying to play a video from my iOS app when tapping a button, but I was wondering how and where I can host my video (for free) so that I can play the video in an AVPlayer using the URL. I tried hosting the video on youtube, and setting the AVPlayer URL to the youtube video URL, but the player loads forever. I included my code, it's functional, I just need to know where I can upload my video to get a proper URL.
#IBAction func didTapPlayButton(_ sender: UIButton) {
guard let url = URL(string: "") else {
return
}
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
let player = AVPlayer(url: url)
// Create a new AVPlayerViewController and pass it a reference to the player.
let controller = AVPlayerViewController()
controller.player = player
// Modally present the player and call the player's play() method when complete.
present(controller, animated: true) {
player.play()
}
}
You need to host and serve your video as a binary file.
You can use an object storage (e.g. Firebase Storage or AWS S3) or serve the file through a web API.
Just set the correct Content-Type (e.g. "video/mp4" to help the player recognise the binary file type)
You can then initiate your AVPlayer with the URL of the video.
Please note that Firebase Storage has a very generous free tier, it might be all you need.
For example:
You can take a look at this video file:
https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4
This file is hosted as a binary and the Content-Type is set to video/mp4.
Try to initiate your AVPlayer with the above URL and see that it works.

Hls stream url wont play in AVPlayer

I am trying to play an hls live stream from a url that looks like this: "http://ip.address:port/my%20video.m3u8". Whenever the url does not involve any spaces the video plays fine otherwise it does not play. There is no error logged from the player but the player itself is just a black screen. I enabled "Allow Arbitrary Loads" and still no dice. When I try loading the urls with spaces in safari the video will play. Here is my code to load and play the video:
DispatchQueue.main.async {
var player = AVPlayer(url: url!)
var playerLayer: AVPlayerLayer!
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resize
self.videoView.layer.addSublayer(playerLayer)
playerLayer.frame = self.videoView.bounds
player.play()
}
What I also find odd is when I try sending the stream to a AVPlayerViewController the player pops up but does not play. Here is how I am sending it to the view controller:
DispatchQueue.main.async {
let player = AVPlayer(url: urlTwo)
let playerController = AVPlayerViewController()
playerController.player = player
present(playerController, animated: true) {
player.play()
}
}
Please check the m3u8 file may be the content in m3u8 have some directory issue. .ts segment and .key file was mentioned in m3u8 file. And when you pass m3u8 to avplayer it fetch the key and .ts file automatically and decrypt the .ts with the mentioned key. Just cross check you m3u8 for key and .ts file.
Also, .key and .ts files need to be in same folder along with m3u8 otherwise it will not fetch and player keep looking for the key and ts.
#EXTM3U
#EXT-X-TARGETDURATION:12
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-VERSION:4
#EXT-X-KEY:METHOD=AES-128,URI="title.key"
#EXTINF:10.0100,
#EXT-X-BYTERANGE:943584#0
title.ts
Something like this.
Note: Sometimes m3u8 and key file have additional encryption which you need to decrypt on run time. I suggest open it in text editor and see if you can see something like given structure above. If it has something unreadable then you need to decrypt it first on run time. If you are using local server and loading file from cache then save the m3u8 file after decryption with Encoding.utf8 and .key file with Encoding.macOSRoman. Otherwise it will not gonna work. Cheers.

Streaming audio with avplayer long buffering - playImmediatelyAtRate doesn't work

I'm streaming audio in my iOS swift app.
The main issue is that avplayer has to load all the file to start the playback.
Using playImmediatelyAtRate doesn't work because playbackBufferEmpty is always true until the file is completely downloaded which can be an issue on long audio files.
Any ideas?
Not really AVPlayer related answer but you could use VLCKit to handle the stream.
Here is a basic sample in Swift:
let mediaPlayer = VLCMediaPlayer()
// replace streamURL by the url of the stream
mediaPlayer.media = VLCMedia(url: streamURL)
// outputView is the view where you want to display the stream
mediaPlayer.drawable = outputView
mediaPlayer.play()
If you have any issue with VLCKit, feel free to ping me!
For iOS >10 I set:
avplayer.automaticallyWaitsToMinimizeStalling = false;
and that seemed to fix it for me. This could have other consequences, but I haven't hit those yet.
I got the idea for it from:
AVPlayer stops playing video after buffering

How to refresh the .m3u8 file, ie., the url used by the AVPlayer in case of Live broadcast?

I have used an AVPlayer object to fetch the .m3u8 file from a remote server and play the video. My application has to stream live data, wherein the .m3u8 file would be updated (either new .ts files are added to the existing contents or the old ones are removed prior adding new .ts files) regularly. How do I make my AVPlayer respond to changing contents on server data. Precisely how to re-assign the url to AVPlayer. Below is the concise code. Please advise.
-(void) playVideo{
AVPlayerItem *contentPlayerItem = [[AVPlayerItem alloc]initWithURL:[NSURL URLWithString:contentURL]]; // contentURL contains the path of live streaming data.
self.contentPlayer = [AVPlayer playerWithPlayerItem:contentPlayerItem]; //content player is an object of type AVPlayer
AVPlayerLayer *avPlayerLayer =
[AVPlayerLayer playerLayerWithPlayer:self.contentPlayer];
//Then I add the AVPlayerLayer object onto my current view after setting its frame.
}
The question is when and how do I refresh the url, assuming the video is being played currently?

Resources