Associate AVPlayerItem with new AVPlayer in Swift? - ios

How can I reassociate an instance of AVPlayerItem with a new AVPlayer in Swift? When used in an initializer. Every time I try to reassign an AVPlayerItem to a different AVPlayer even after I've set all references to the AVPlayer to nil (so it should get garbage collected), it complains that an AVPlayerItem cannot be assigned to more than 1 AVPlayer object. I understand a few ways to get around it but I want to know why this way doesn't work.
let player: AVPlayer = AVPlayer(playerItem: somePlayerItem)
I don't know what happens during this declaration but something somewhere gets set to allow somePlayerItem know it has an associated player. Does this have some observer set somewhere or property set that would note this?
Does anyone know a way to reassign this AVPlayerItem to a different AVPlayer after the original AVPlayer's references have been destroyed? I know I can just make a new AVPlayerItem using the URL but I want to know if I can keep the same object.

You can't reuse an item, but you can reuse an asset.
So create your asset once:
let asset=AVAsset(URL: your_url)
Then reuse it when needed by creating a new item:
let item=AVPlayerItem(asset: asset)
let player=AVPlayer(playerItem: item)

Related

How to disconnect AVPlayer from AVPlayerItem?

I want to reuse an AVPlayerItem but keep getting this error:
An AVPlayerItem cannot be associated with more than one instance of AVPlayer
Before trying to reuse it, I destroy the previous AVPlayer like this:
[self.player pause];
[self.player replaceCurrentItemWithPlayerItem:nil];
self.player = nil;
why is the AVPlayerItem still associated and how can I disconnect it?
Here is a Gist with a full reproduction of the problem (only 50 lines btw): https://gist.github.com/sbiermanlytle/14a6faab515f7691b810789086ae9e50
You can run it by creating a new Single View app, and supplanting the ViewController implementation with that code.
You can't disconnect AVPlayerItems. I guess the private property that points to the player is not weak, so dereferencing the item by setting current player item to NULL does not automatically set the item's player property to NULL..
Simply create a new one. Either with the URL, in which case the cache system will return an AVAsset instantly ( Just another guess... ), or, better, with the asset of the PlayerItem you want to 'disconnect'.
AVPlayerItem* newPlayerItem = [AVPlayerItem playerItemWithAsset:playerItem.asset];
There is no performance loss doing this. The item is just a 'handle' to the asset, which contains the data for real. So don't be afraid to trash and create new items on the fly.

How to pause/resume avplayer preload

I'm using AVPlayer to play video from Internet, is there a way to pause/resume preloading video when pause/resume playing?
One way to do that would be to save your AVURLAsset to a variable (tempAsset = player.playerItem.asset), and then replace the playerItem in your player with nil. When you are ready to play it again, you can create a new playerItem from the asset that you saved previously.
I have same problem and i used buffer limit to stop preloading in my code.
This works for me.
You can also try setting buffer limit to stop preloading video when you click on Pause or Resume.
I hope this will help you.
The duration the player should buffer media from the network ahead of the playhead to guard against playback disruption.
player.currentItem?.preferredForwardBufferDuration
When you work with AVPlayerItem you can set time interval for the buffer. Example:
AVPlayerItem(). preferredForwardBufferDuration = TimeInterval(exactly: 100)!

Play Song at specific index of MPMediaItemCollection in Swift

I try to make my own Musicplayer with Swift. I need to jump to a specific song/index of my MPMediaItemCollection and start to play it but i can only find methods like skipToNextItem() and skipToPreviousItem(). Is there any other way to do that than with a loop?
let player = MPMusicPlayerController.systemMusicPlayer()
player.setQueueWithItemCollection(mediaCollection)
player.play()
According to the documentation, we use the nowPlayingItem property.
To specify that playback should begin at a particular media item in the playback queue, set this property to that item while the music player is stopped or paused.
So, it sounds like you should stop or pause the player, set the nowPlayingItem, and then call play again.
player.nowPlayingItem = mediaCollection.items[selectedIndex]
player.play()

Why doesn't AVPlayer stop loading data?

When I watch my mac's network connectivity I can tell that a movie is still buffering even after I remove the view which had the AVPlayer on it.
Does anyone know how to force AVPlayer to stop loading data?
Maybe it's late to answer this question, but I've just solved the same one.
Just save here in case anyone need...
[self.player.currentItem cancelPendingSeeks];
[self.player.currentItem.asset cancelLoading];
There's no cancel method in AVPlayer class, but in AVPlayerItem and AVAsset class, there are!
PS: player here is AVPlayer class, not AVQueuePlayer class.
An AVPlayer is not a view. You may have "removed the view" but that does not mean you have removed or stopped the AVPlayer. I would guess that the way to do what you want is to destroy the AVPlayer itself.
I figured it out.
When you want to stop an AVPlayerItem from loading, use AVQueuePlayer's removeAllItems and then re-initialize it.
[self.avPlayer removeAllItems];
self.avPlayer = [AVQueuePlayer playerWithURL:[NSURL URLWithString:#""]];
self.avPlayer = nil;
This will stop the current item from loading -- it is the only way I found to accomplish this.

Multiple AVPlayers on Separate UIViewControllers

I have multiple AVPlayers, each on separate UIViewControllers playing different songs.
I need to pause one AVPlayer whenever I play another one (otherwise the audio overlaps).
I would like to let the user traverse through the app while the music plays in the background, so pausing the AVPlayer on viewDidDisappear:(BOOL)animated, would not work.
What is the best way to access the controls of each separate AVPlayer?
In my opinion a singleton with only 1 AVPlayer solves this issue well. This way you guarantee that to play another song you have to stop the previous. Then, in that AVPLayerSingleton you have a private property called avPlayer. You can define two methods:
- (void)createPlayerWithSong:(NSString *)currentSong;
- (void)destroyPlayer
Then, in your createPlayerWithSong you can check if avPlayer is already created and destroy it and create a new one for each new song.
Couple of ways you could do it:
Create a shared singleton object that have weak properties that reference each AVPlayer. That way you can control it from anywhere.
OR
Use NSNotificationCenter to send notifications when you want to control an AVPlayer on a different view controller. This might get cumbersome if you have a lot of AVPlayers you want to control.

Resources