AVPlayer Play, Pause and Buffering issue - ios

My app plays a streaming video, but when it buffers, the player goes to the pause mode and I have to set it to play mode again manually, I have the following code in my AVPlayer class in order to handle this situation, but it does not work.
In the ViewDidLoad method
[playerItem addObserver:self forKeyPath:#"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[playerItem addObserver:self forKeyPath:#"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
and then, handling the observers using the following methods
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (!player)
{
return;
}
else if (object == playerItem && [keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (playerItem.playbackBufferEmpty) {
//Your code here
}
}
else if (object == playerItem && [keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
if (playerItem.playbackLikelyToKeepUp)
{
//Your code here
}
}
}
is there a another solution for this problem in order to get the player to continues play mode?

This might help,
suppose this is your AVPlayer object
player1 = [AVPlayer playerWithURL:streamURL];
When your video goes in buffer mode then you can pause it and when it done play it again like:
In observer method,
if ([object isKindOfClass:[AVPlayerItem class]])
{
AVPlayerItem *item = (AVPlayerItem *)object;
//playerItem status value changed?
if ([keyPath isEqualToString:#"status"])
{ //yes->check it...
NSLog(#"STATUS = %d",item.status);
switch(item.status)
{
case AVPlayerItemStatusFailed:
NSLog(#"player item status failed");
break;
case AVPlayerItemStatusReadyToPlay:
[playButton setTitle:#"Pause" forState:UIControlStateNormal];
[player1 play];
NSLog(#"player item status is ready to play");
break;
case AVPlayerItemStatusUnknown:
NSLog(#"player item status is unknown");
break;
}
}
else if ([keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (item.playbackBufferEmpty)
{
[playButton setTitle:#"Play" forState:UIControlStateNormal];
[player1 pause];
NSLog(#"player item playback buffer is empty");
}
}
}
or you can maintain on button click event.
Place one button on your screen to maintain play and pause and addTarget to it with OnClick event.

Related

AvPlayer streaming, all the metadata information are in timedMetadata?

I'm creating an ios app with a streaming player maded with AvPlayer. This is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self InitPlayer];
[self ReadMetaData];
}
-(void)InitPlayer{
NSURL *url = [[NSURL alloc] initWithString:#"http://www.fakeurl.com/stream"];
// create a player view controller
self.player = [AVPlayer playerWithURL:url];
player.closedCaptionDisplayEnabled = NO;
}
-(void)ReadMetaData{
[self.player.currentItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
}
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object
change:(NSDictionary*)change context:(void*)context {
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* playerItem = object;
for (AVMetadataItem* metadata in playerItem.timedMetadata)
{
if([metadata.commonKey isEqualToString:#"title"]){
TitleLabel.text=metadata.stringValue;
}
}
}
}
With this code i can successfully play and pause the stream. I can also print the title of the track.
If i try to log the timedMetadata with something like this:
NSLog(#"%#",player.currentItem.timedMetadata);
I retrive that:
"<AVMetadataItem: 0x15649500, identifier=common/title, keySpace=comn, key class = __NSCFConstantString, key=title, commonKey=title, extendedLanguageTag=(null), dataType=(null), time={21888/44100 = 0.496}, duration={INVALID}, startDate=(null), extras={\n}, value=Keepin-'fake song title>"
Now my question is: for that specific stream url the timedMetadata i logged are the only metadata i can retrive? If yes how i can achive a more complex player type (something like "go to next track button","go to previous track button","an history of tracks",ecc...) ? That's the first time i work with stream data and in my expectations there was a lot of information in audio metadata. In real life seems i can get only the track title. There's a problem with my code or the stream source is poor in metadata info?
I tried to find best solution to get metadata from AVPlayer and found it:
-(IBAction) BtnGoClick:(id)sender {
NSURL *url = [[NSURL alloc] initWithString:#"http://cast.loungefm.com.ua/loungefm"];
[self setupAVPlayerForURL:url];
}
-(void) setupAVPlayerForURL: (NSURL*) url {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:anItem];
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
[anItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == player && [keyPath isEqualToString:#"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(#"AVPlayer Failed");
} else if (player.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayer Ready to Play");
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* playerItem = object;
for (AVMetadataItem* metadata in playerItem.timedMetadata)
{
if([metadata.commonKey isEqualToString:#"title"]){
NSLog(#"%#",metadata.stringValue);
}
}
}
}
Result:

AvPlayer hangs and stop streaming big size audio url

I am using AvPlayer to stream and play audio file from url. my code is working fine with small size url but stop playing big size audios.please help me to resolve this issue..
here is my code
-(void)playAudioFeeds:(NSString *)audioStr{
AVPlayerItem *audioPlayerItem;
[self enableObserver:NO onObject:audioPlayerItem addObserver:self];
audioPlayerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:audioStr]];
[self enableObserver:YES onObject:audioPlayerItem addObserver:self];
self.audioFeedsPlayer = [[AVPlayer alloc]initWithPlayerItem:audioPlayerItem];
[self.audioFeedsPlayer play];
}
and code to add observer is..
- (void)enableObserver:(BOOL)enable onObject:(AVPlayerItem *)object addObserver:(id)observer {
if (enable) {
[object addObserver:observer forKeyPath:#"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
[[object valueForKey:#"player"] addObserver:self forKeyPath:#"status" options:0 context:nil];
NSLog(#"Enable KYObserver");
} else {
#try {
[object removeObserver:observer forKeyPath:#"playbackLikelyToKeepUp" context:nil];
[[object valueForKey:#"player"] removeObserver:self forKeyPath:#"status" context:nil];
NSLog(#"Remove KYObserver");
} #catch (NSException *__unused exception) {
NSLog(#"Exceptions occurs on removing the KYObserver");
}
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// check that all conditions for a stuck player have been met
AVPlayer *player = [object valueForKey:#"player"];
NSLog(#"In OVKP of songPlayer");
NSLog(#"keyPath:%#",keyPath);
if ([keyPath isEqualToString:#"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(#"AVPlayer Failed");
} else if (player.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayerStatusReadyToPlay");
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
if ([keyPath isEqualToString:#"playbackLikelyToKeepUp"]) {
if (player.currentItem.playbackLikelyToKeepUp == NO &&
CMTIME_COMPARE_INLINE(player.currentTime, >, kCMTimeZero) &&
CMTIME_COMPARE_INLINE(player.currentTime, !=, player.currentItem.duration))
{
NSLog(#"Hanged");
[player performSelector:#selector(play) withObject:nil afterDelay:1];
}
}
}

Objective-c , AVPlayer taking too much time to Resume play audio from URL

I have implemented AVPlayer. It is working fine. But many times during playing audio from URL, it stops/pauses automatically and takes very long time to resume/replay. On the other hand if I manually just pause and play it works fine means it does not take too much time to re-play. I want to resume/replay it whenever it is ready. Any suggestion will be great. Thank in advance !!!!!!!!
My code :
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (!songFinished) {
if (object == playerItem && [keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (playerItem.playbackBufferEmpty) {
printf("\n\n\t****player item playback buffer is empty****\n\n");
//[s activityIndicator] startAnimating];
[player pause];
}
}
else if (object == playerItem && [keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
if (playerItem.playbackLikelyToKeepUp)
{
printf("\n\n\t****Ready to Play audio ****\n\n");
[player play];
//Your code here
}
}
// for player status ------------------------------------------------------
else if (object == player && [keyPath isEqualToString:#"status"])
{
if (player.status == AVPlayerStatusFailed)
{
printf("\n\n\tAVPlayer Failed\n\n");
[ViewUtilities showAlert:AUDIO_PLAYER :AUDIO_PLAYER_FAILED_MESSAGE];
}
else if (player.status == AVPlayerStatusReadyToPlay)
{
printf("\n\n\tAVPlayerStatusReadyToPlay\n\n");
[player play];
nsTimer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
}
else if (player.status == AVPlayerItemStatusUnknown)
{
[ViewUtilities showAlert:AUDIO_PLAYER :AUDIO_PLAYER_UNKNOWN];
printf("\n\n\tAVPlayer Unknown\n\n");
}
if (!player)
{
return;
}
}
}
}

AVPlayerItem: KVO for multiple tracks

I've been trying to register my AVQueuePlayer items for KVO at the time of initializing. Below, the items in itemArray have all been properly created with URLs. After the code the queueList is added to a AVQueuePlayer. The player plays fine, with each item playing in order, but only observers for the first item trigger the response. The AVPlayerItemDidPlayToEnd works for all items, however.
I'm fairly new to KVO. Any help would be appreciated.
for(AVPlayerItem *i in itemArray)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(nextSong)
name:AVPlayerItemDidPlayToEndTimeNotification object:i];
[i addObserver:self forKeyPath:#"status" options:0 context:nil];
[i addObserver:self forKeyPath:#"playbackBufferEmpty" options:0 context:nil];
[i addObserver:self forKeyPath:#"playbackLikelyToKeepUp" options:0 context:nil];
[queueList addObject:item];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
AVPlayerItem *thisItem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:#"rate"]) {
if ([self.player rate]!=0) {
[self setPlayButtonAsPlaying:YES];
NSLog(#"PLAYING");
}
else {
[self setPlayButtonAsPlaying:NO];
NSLog(#"PAUSED");
}
}
else if ([keyPath isEqualToString:#"status"])
{
if(thisItem.status==AVPlayerItemStatusFailed)
{
NSLog(#"failed");
[self setPlayButtonAsPlaying:NO];
[player pause];
}
}
else if ([keyPath isEqualToString:#"playbackBufferEmpty"])
{
if(thisItem.playbackBufferEmpty)
{
[player pause];
[self setPlayButtonAsPlaying:NO];
}
}
else if ([keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
if(!thisItem.playbackLikelyToKeepUp)
{
[player pause];
[self setPlayButtonAsPlaying:NO];
}
else
{
[player play];
[self setPlayButtonAsPlaying:YES];
}
}
}
EDIT: I also have a button which triggers this command, which I use to test the state of these properties.
NSLog(player.currentItem.playbackBufferEmpty ? #"Yes" : #"No");
NSLog(player.currentItem.playbackLikelyToKeepUp ? #"Yes" : #"No");
Specifically, playbackLikelyToKeepUp is false (which I manually cause by disconnecting my wifi). Interestingly, the playBackBufferEmpty is also false.

AVPlayer status always AVPlayerStatusReadyToPlay

I am using AVPlayer to play audio from a URL
In ViewDidLoad:
self.playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:imageText]];
self.player = [AVPlayer playerWithPlayerItem:playerItem];
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
[player play];
Observer
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (object == player && [keyPath isEqualToString:#"status"]) {
if (player.status == AVPlayerStatusReadyToPlay) {
//[playingLbl setText:#"Playing Audio"];
NSLog(#"fineee");
[playBtn setEnabled:YES];
} else if (player.status == AVPlayerStatusFailed) {
// something went wrong. player.error should contain some information
NSLog(#"not fineee");
NSLog(#"%#",player.error);
}
else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
}
but the player sometimes is stuck and does not play the audio but then also status is AVPlayerStatusReadyToPlay. It never goes inside AVPlayerStatusFailed or AVPlayerItemStatusUnknown. As i want to handle AVPlayer's error, it must go inside these as well. Please help!!
You should observe CurrentItem's status. AVPlayer failed because of AVPlayerItem failed, if anythings went wrong, it begins from AVPlayerItem then AVPlayer.
try:
[item addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
in your observeValueForKeyPath:
if (object == audioPlayer.currentItem && [keyPath isEqualToString:#"status"]) {
if (audioPlayer.currentItem.status == AVPlayerItemStatusFailed) {
NSLog(#"------player item failed:%#",audioPlayer.currentItem.error);
}
}
You can take a look of AVPlayer's handling or use it directly from HysteriaPlayer, my open source project.

Resources