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];
}
}
}
Related
Hi I am trying to play live streaming api in my app but their is some error occurs like below...
Response Fail. Error : The operation couldn’t be completed. (Cocoa
error 3840.)
please help to sort out this problem
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",arrayId);
Service *srv=[[Service alloc]init];
NSString *str=#"http://streamtvbox.com/site/api/matrix/";
NSString *method=#"channel";
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setValue:arrayId forKey:#"id"];
[srv postToURL:str withMethod:method andParams:dict completion:^(BOOL success, NSDictionary *responseObj)
{
if (success) {
NSLog(#"Hello I am success");
}
NSLog(#"%#",responseObj);
_player = [[MPMoviePlayerViewController alloc] initWithContentURL:responseObj];
[self presentMoviePlayerViewControllerAnimated:_player];
}];
}
AVPlayerItem is the best choice in this case as you have more control.
See the below code snippet. I have given you just basic example. You do some re-search on AVPlayerItem.
Define your AVPlayer object:
AVPlayer *videoPlayer;
Prepare AVPlayer and add Observers:
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:imageText]];
videoPlayer = [AVPlayer playerWithPlayerItem:playerItem];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[videoPlayer currentItem]];
[videoPlayer addObserver:self forKeyPath:#"status" options:0 context:nil];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateProgress:) userInfo:nil repeats:YES];
Handling callbacks:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == videoPlayer && [keyPath isEqualToString:#"status"])
{
if (videoPlayer.status == AVPlayerStatusFailed)
{
NSLog(#"AVPlayer Failed");
}
else if (videoPlayer.status == AVPlayerStatusReadyToPlay)
{
NSLog(#"AVPlayerStatusReadyToPlay");
[videoPlayer play];
}
else if (videoPlayer.status == AVPlayerItemStatusUnknown)
{
NSLog(#"AVPlayer Unknown");
}
}
if (object == videoPlayer && [keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
if (videoPlayer.playbackLikelyToKeepUp)
{
// Hide Activity indicator
[videoPlayer play];
}
}
if (object == videoPlayer && [keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (videoPlayer.playbackBufferEmpty)
{
// Show Activity indicator
[videoPlayer pause];
}
}
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
// code here whatever you want to do on finishing video stream..
}
Hi i created Avplayer for playing audio from server and its working perfectly but UISlider is not syncing with Audio even after updating UISlider method but the slider is moving properly but its not syncing with audio.i need to match that audio with UISlider
seekbar =[[UISlider alloc]init];
seekbar.frame=CGRectMake(10,CGRectGetMinY(PlayAudio.frame)-50, CGRectGetWidth(self.view.frame)-20, 20);
[seekbar addTarget:self action:#selector(seektime:) forControlEvents:UIControlEventValueChanged];
seekbar.continuous=YES;
[self.view addSubview:seekbar];
-(void)Audio{
NSString *urlString= #"https:/embed-ssl.wistia.com/deliveries/85dcf8de9db3830f47f136a4dba89114be58403f/dhwpxq4l9l.wav";
audioPlayer = [[AVPlayer alloc]initWithURL:[NSURL URLWithString:urlString]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[audioPlayer currentItem]];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
[audioPlayer play];
NSLog(#"Audio playing");
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == audioPlayer && [keyPath isEqualToString:#"status"]) {
if (audioPlayer.status == AVPlayerStatusFailed) {
NSLog(#"AVPlayer Failed");
} else if (audioPlayer.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayerStatusReadyToPlay");
[audioPlayer play];
} else if (audioPlayer.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
}
- (void)seektime:(UISlider*)sender {
CGFloat currentSongTime = CMTimeGetSeconds([audioPlayer currentTime]);
seekbar.value = currentSongTime;
seekbar.minimumValue=0;
seekbar.maximumValue=currentSongTime;
}
- (void)updateProgress {
[seekbar setValue:CMTimeGetSeconds(audioPlayer.currentTime)];
}
Why are you changing the maximum value at every change?
You can set the minimumValue and maximumValue when you get AVPlayerStatusReadyToPlay according to audioPlayer.currentItem.duration
So instead of the seektime you can just use:
else if (audioPlayer.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayerStatusReadyToPlay");
[audioPlayer play];
seekbar.minimumValue = 0;
seekbar.maximumValue = CMTimeGetSeconds(audioPlayer.currentItem.duration);
}
I have this issue and this is not so easy as I thought.... I lost some of time and nothing yet.
And I know, I have a method pause, but I want to stop and start and avoid crash the application..
Could anyone help, very thanks.
//First.
-(void) setupAVPlayerForURL{
#try {
NSURL *url = [[NSURL alloc] initWithString:URL_RADIO_STREAM];
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
anItem = [AVPlayerItem playerItemWithAsset:asset];
[anItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[anItem addObserver:self forKeyPath:#"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[anItem addObserver:self forKeyPath:#"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
player = [AVPlayer playerWithPlayerItem:anItem];
//[player addObserver:self forKeyPath:#"status" options:0 context:nil];
}
#catch (NSException *exception) {
NSLog(#"%#", exception.reason);
[[self textDebug]setText : exception.description];
}
}
//After.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
/*if (!player)
{
return;
}*/
if ([object isKindOfClass:[AVPlayerItem class]])
{
AVPlayerItem *playerItem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:#"status"])
{ //yes->check it...
switch(playerItem.status)
{
case AVPlayerItemStatusFailed:
NSLog(#"player item status failed");
self.BtnPlay.userInteractionEnabled = FALSE;
break;
case AVPlayerItemStatusReadyToPlay:
NSLog(#"player item status is ready to play");
self.BtnPlay.userInteractionEnabled = TRUE;
break;
case AVPlayerItemStatusUnknown:
NSLog(#"player item status is unknown");
self.BtnPlay.userInteractionEnabled = FALSE;
break;
}
}
if ([keyPath isEqualToString:#"playbackBufferEmpty"])
{
NSLog(#"player item status playbackBufferEmpty");
if (playerItem.playbackBufferEmpty) {
//Your code here
[[NSNotificationCenter defaultCenter] postNotificationName:#"message" object:#"Buffering..."];
if([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
[self setupAVPlayerForURL];
}];
}
}
}
if ([keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
NSLog(#"player item status playbackLikelyToKeepUp");
if (playerItem.playbackLikelyToKeepUp)
{
//Your code here
[player play];
if([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
[[UIApplication sharedApplication] endBackgroundTask:task];
task = 0;
}
}
}
}
}
//Finally.
-(IBAction) BtnPlay:(id)sender {
if(self.BtnPlay.touchInside){
if (player.rate == 1.0) {
[player pause];
[BtnPlay setTitle:#"Play" forState:UIControlStateNormal];
} else {
[player play];
[BtnPlay setTitle:#"Pause" forState:UIControlStateNormal];
}
}
}
//But I don't know how to Stop this instead pause...
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.
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.