AVPlayer does not use prelload - ios

I have a problem when I try to play some remoute audio file.
For this I use AvPlayer.
How you know for play something at first we start preload:
init AVURLAsset
set observer
init avplayer
example:
if (trackUrl) {
self.asset = [AVURLAsset assetWithURL:trackUrl];
NSArray *assetKeys = #[#"playable", #"hasProtectedContent"];
self.playerItem = [AVPlayerItem playerItemWithAsset:self.asset
automaticallyLoadedAssetKeys:assetKeys];
NSKeyValueObservingOptions options =
NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
[self.playerItem addObserver:self
forKeyPath:#"status"
options:options
context:playerItemContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(trackDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
[self removePeriodicTimeObserver];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
return;
}
So, for audio file which does not have this field at response header "content-disposition:" everything works fine. Preload process is really fast.
example: http://podcast.cbc.ca/mp3/podcasts/asithappens_20160907_50906.mp3
But for audio file which has this field at response header "content-disposition:". Preload process is really long.
example: https://ondemand.npr.org/anon.npr-mp3/npr/fa/2017/01/20170124_fa_01.mp3?orgId=427869011&topicId=1033&d=2209&p=13&story=511387528&t=progseg&e=511402985&seg=1&siteplayer=true&dl=1
It looks like AvPlayer tries to load all file and only after that play this.
Question:
Do you know how I can omit this long preload?
How can I miss this field "content-disposition:" at response?

Related

Vine’s Infinite Video Loops in iOS 9 (seamlessly video)

I need some help with Infinite Video Loops like a Vine did.
I tried a lot of approaches and all of them have a short delay.
One of most popular:
__weak typeof(self) weakSelf = self; // prevent memory cycle
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
object:nil // any object can send
queue:nil // the queue of the sending
usingBlock:^(NSNotification *note) {
// holding a pointer to avPlayer to reuse it
[weakSelf.avPlayer seekToTime:kCMTimeZero];
[weakSelf.avPlayer play];
}];
Is there any way to eliminate the delay and play local videos seamlessly?
I know that Apple add some updates in iOS 9, but I need that it work from 8+ ios
Sorry for Ojc-C sample, I use Swift
Try this
-(void)startPlaybackForItemWithURL:(NSURL*)url {
// First create an AVPlayerItem
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:url];
// Subscribe to the AVPlayerItem's DidPlayToEndTime notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
// Pass the AVPlayerItem to a new player
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
// Begin playback
[player play]
}
-(void)itemDidFinishPlaying:(NSNotification *) notification {
[self.avPlayer play];
// Will be called when AVPlayer finishes playing playerItem
}

Replaying AVPlayerItem / AVPlayer without re-downloading

I have an AVPlayer class all set up that streams an audio file. It's a bit long, so I can't post the whole thing here. What I am stuck on is how to allow the user to replay the audio file after they have finished listening to it once. When it finishes the first time, I correctly receive a notification AVPlayerItemDidPlayToEndTimeNotification. When I go to replay it, I immediately receive the same notification, which blocks me from replaying it.
How can I reset this such that the AVPlayerItem doesn't think that it has already played the audio file? I could deallocate everything and set it up again, but I believe that would force the user to download the audio file again, which is pointless and slow.
Here are some parts of the class that I think are relevant. The output that I get when attempting to replay the file looks like this. The first two lines are exactly what I would expect, but the third is a surprise.
is playing no timer audio player has finished playing audio
- (id) initWithURL : (NSString *) urlString
{
self = [super init];
if (self) {
self.isPlaying = NO;
self.verbose = YES;
if (self.verbose) NSLog(#"url: %#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
self.playerItem = [AVPlayerItem playerItemWithURL:url];
self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];
[self determineAudioPlayTime : self.playerItem];
self.lengthOfAudioInSeconds = #0.0f;
[self.player addObserver:self forKeyPath:#"status" options:0 context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
}
return self;
}
// this is what gets called when the user clicks the play button after they have
// listened to the file and the AVPlayerItemDidPlayToEndTimeNotification has been received
- (void) playAgain {
[self.playerItem seekToTime:kCMTimeZero];
[self toggleState];
}
- (void) toggleState {
self.isPlaying = !self.isPlaying;
if (self.isPlaying) {
if (self.verbose) NSLog(#"is playing");
[self.player play];
if (!timer) {
NSLog(#"no timer");
CMTime audioTimer = CMTimeMake(0, 1);
[self.player seekToTime:audioTimer];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateProgress)
userInfo:nil
repeats:YES];
}
} else {
if (self.verbose) NSLog(#"paused");
[self.player pause];
}
}
-(void)itemDidFinishPlaying:(NSNotification *) notification {
if (self.verbose) NSLog(#"audio player has finished playing audio");
[[NSNotificationCenter defaultCenter] postNotificationName:#"audioFinished" object:self];
[timer invalidate];
timer = nil;
self.totalSecondsPlayed = [NSNumber numberWithInt:0];
self.isPlaying = NO;
}
You can call the seekToTime method when your player received AVPlayerItemDidPlayToEndTimeNotification
func itemDidFinishPlaying() {
self.player.seek(to: CMTime.zero)
self.player.play()
}
Apple recommends using AVQueueplayer with an AVPlayerLooper.
Here's Apple's (slightly revised) sample code:
AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] init];
AVAsset *asset = // AVAsset with its 'duration' property value loaded
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
// Create a new player looper with the queue player and template item
self.playerLooper = [AVPlayerLooper playerLooperWithPlayer:queuePlayer
templateItem:playerItem];
// Begin looping playback
[queuePlayer play];
The AVPlayerLooper does all the event listening and playing for you, and the queue player is used to create what they call a "treadmill pattern". This pattern is essentially chaining multiple instances of the same AVAssetItem in a queue player and moving each finished asset back to the beginning of the queue.
The advantage of this approach is that it enables the framework to preroll the next asset (which is the same asset in this case, but its start still needs prerolling) before it arrives, reducing latency between the asset's end and looped start.
This is described in greater detail at ~15:00 in the video here: https://developer.apple.com/videos/play/wwdc2016/503/

ios AVPlayer failed to stream remote video

I have a AVPlayer that plays video from remote url.
Here is my code:
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:videoUrl];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.frame = playerView.bounds;
[playerView.layer addSublayer:playerLayer];
[self.player play];
When I start to stream I have only less then a second video chunck and then downloading stops and nothing happens.
MPMoviePlayerController and browser plays this video as usual.
I also doubt, that it might be effect of cropping video (because videos without cropping works fine). Here is the guide I use to crod video http://www.one-dreamer.com/cropping-video-square-like-vine-instagram-xcode/
Also clean app with same setup can't play video.
Any ideas? thanks!
Use the AVPlayerItemPlaybackStalledNotification
[[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemPlaybackStalledNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[weakself performBlockOnMainQueueAfterDelay:1.5 block:^{
[weakself.player play];
}];
}];

AVPlayer iphone to play sound even views are changed

I am developing a music player app where the tracks or sounds are played from the url and I m using AVplayer to play the tracks from the url
Basically i want to keep on playing the tracks even user navigated or goes to new other or the application goes to background !! i really don't have a idea how to achieve the same..
these is the demo code I am using to get the track from the URL
NSURL *url = [NSURL URLWithString:#"<#Live stream URL#>];
// You may find a test stream at <http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8>.
self.playerItem = [AVPlayerItem playerItemWithURL:url];
//(optional) [playerItem addObserver:self forKeyPath:#"status" options:0 context:&ItemStatusContext];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
self.player = [AVPlayer playerWithURL:<#Live stream URL#>];
//(optional) [player addObserver:self forKeyPath:#"status" options:0 context:&PlayerStatusContext];
i even wanted to play next track if the current played track is over.

AVPlayerItem and KVO - am i missing something?

so in the init of a simple Controller i have this code:
self.playerItem = [AVPlayerItem playerItemWithURL:url];
[self.playerItem addObserver:self forKeyPath:#"status" options:0 context:nil];
which should try and load media from the url, right? i'm implemeting
observeValueForKeyPath:ofObject:change:context:
however, this method is never called. Clueless?
playerItem starts working after being assigned to a AVPlayer object (duh)
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];

Resources