I am getting the error within the app
" Assertion failure in -[AVPlayerPeriodicCaller initWithPlayer:interval:queue:block:], /SourceCache/EmbeddedAVFoundation/EmbeddedAVFoundation-461.12/Fig/AVPlayer.m:3993
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: CMTIME_COMPARE_INLINE(interval, >, kCMTimeZero)'
Any ideas why this may be happening?
I am limited to use AvPlayer only because I need to stream large file .AVaudioplayer is not an option. So I have also implemented a scrubber slider. My implementation of AVplayer is as follows:
-(void)playAudioForFile:(NSString *)fileName{
[self.suraPlayer removeTimeObserver:playbackObserver];
[self.suraPlayer removeTimeObserver:mTimeObserver];
self.suraPlayer = nil;
NSURL* url = [self getURLStringForFileName:fileName];
AVPlayer *player = [[AVPlayer alloc]initWithURL:url];
self.suraPlayer = player;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[suraPlayer currentItem]];
[self.suraPlayer play];
[self.suraPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];
[self initScrubberTimer];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
//[self metadataForAsset:self.suraPlayer.currentItem.asset];
}
-(void)updateProgress {
// NSLog(@"self.mScrubber.value %f", self.mScrubber.value);
//THIS IS THE LINE WHERE THE DEBUGGER SOMETIME STUMPS
float duration = CMTimeGetSeconds(self.suraPlayer.currentItem.duration);
if (self.suraPlayer.currentItem.status==AVPlayerStatusReadyToPlay )
[self.mScrubber setMaximumValue:duration];
self.mScrubber.value = CMTimeGetSeconds(self.suraPlayer.currentTime);
int seconds = self.mScrubber.value, minutes = seconds/60,hours = minutes/60;
int secondsRemain = self.mScrubber.maximumValue - seconds,minutesRemain = secondsRemain/60,hoursRemain = minutesRemain/60;
seconds = seconds-minutes*60;
minutes = minutes-hours*60;
secondsRemain = secondsRemain - minutesRemain*60;
minutesRemain = minutesRemain - hoursRemain*60;
NSString *hourStr,*minuteStr,*secondStr,*hourStrRemain,*minuteStrRemain,*secondStrRemain;
hourStr = hours > 9 ? [NSString stringWithFormat:@"%d",hours] : [NSString stringWithFormat:@"0%d",hours];
minuteStr = minutes > 9 ? [NSString stringWithFormat:@"%d",minutes] : [NSString stringWithFormat:@"0%d",minutes];
secondStr = seconds > 9 ? [NSString stringWithFormat:@"%d",seconds] : [NSString stringWithFormat:@"0%d",seconds];
hourStrRemain = hoursRemain > 9 ? [NSString stringWithFormat:@"%d",hoursRemain] : [NSString stringWithFormat:@"0%d",hoursRemain];
minuteStrRemain = minutesRemain > 9 ? [NSString stringWithFormat:@"%d",minutesRemain] : [NSString stringWithFormat:@"0%d",minutesRemain];
secondStrRemain = secondsRemain > 9 ? [NSString stringWithFormat:@"%d",secondsRemain] : [NSString stringWithFormat:@"0%d",secondsRemain];
self.timePlayerLabel.text = [NSString stringWithFormat:@"%@:%@:%@",hourStr,minuteStr,secondStr];
self.timeRemainingLabel.text = [NSString stringWithFormat:@"-%@:%@:%@",hourStrRemain,minuteStrRemain,secondStrRemain];
}
-(void)initScrubberTimer
{
double interval = .1f;
CMTime playerDuration = self.suraPlayer.currentItem.duration;
if (CMTIME_IS_INVALID(playerDuration))
{
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
CGFloat width = CGRectGetWidth([self.mScrubber bounds]);
interval = 0.5f * duration / width;
}
/* Update the scrubber during normal playback. */
mTimeObserver = [self.suraPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC)
queue:NULL /* If you pass NULL, the main queue is used. */
usingBlock:^(CMTime time)
{
}];
[self syncScrubber];
}
/* Set the scrubber based on the player current time. */
- (void)syncScrubber
{
CMTime playerDuration = self.suraPlayer.currentItem.duration;
if (CMTIME_IS_INVALID(playerDuration))
{
self.mScrubber.minimumValue = 0.0;
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
float minValue = [self.mScrubber minimumValue];
float maxValue = [self.mScrubber maximumValue];
double time = CMTimeGetSeconds([self.suraPlayer currentTime]);
[self.mScrubber setValue:(maxValue - minValue) * time / duration + minValue];
}
}
/* The user is dragging the movie controller thumb to scrub through the movie. */
/* Set the player current time to match the scrubber position. */
- (IBAction)scrub:(id)sender
{
if ([sender isKindOfClass:[UISlider class]])
{
UISlider* slider = sender;
CMTime playerDuration = self.suraPlayer.currentItem.duration;
if (CMTIME_IS_INVALID(playerDuration)) {
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
float minValue = [slider minimumValue];
float maxValue = [slider maximumValue];
float value = [slider value];
double time = duration * (value - minValue) / (maxValue - minValue);
[self.suraPlayer seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];
}
}
}
- (IBAction)beginScrubbing:(id)sender {
mRestoreAfterScrubbingRate = [self.suraPlayer rate];
[self.suraPlayer setRate:0.f];
/* Remove previous timer. */
[self removePlayerTimeObserver];
}
/* The user has released the movie thumb control to stop scrubbing through the movie. */
- (IBAction)endScrubbing:(id)sender {
__weak typeof(self) weakSelf = self;
if (!mTimeObserver)
{
CMTime playerDuration = self.suraPlayer.currentItem.duration;
if (CMTIME_IS_INVALID(playerDuration))
{
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
CGFloat width = CGRectGetWidth([self.mScrubber bounds]);
double tolerance = 0.5f * duration / width;
mTimeObserver = [self.suraPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(tolerance, NSEC_PER_SEC) queue:NULL usingBlock:
^(CMTime time)
{
[weakSelf syncScrubber];
}];
}
}
if (mRestoreAfterScrubbingRate)
{
[self.suraPlayer setRate:mRestoreAfterScrubbingRate];
mRestoreAfterScrubbingRate = 0.f;
}
}
- (BOOL)isScrubbing
{
return mRestoreAfterScrubbingRate != 0.f;
}
-(void)enableScrubber
{
self.mScrubber.enabled = YES;
}
-(void)disableScrubber
{
self.mScrubber.enabled = NO;
}
-(void)removePlayerTimeObserver
{
if (mTimeObserver)
{
[self.suraPlayer removeTimeObserver:mTimeObserver];
mTimeObserver = nil;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == suraPlayer && [keyPath isEqualToString:@"status"]) {
if (suraPlayer.status == AVPlayerStatusFailed) {
NSLog(@"AVPlayer Failed");
} else if (suraPlayer.status == AVPlayerStatusReadyToPlay) {
NSLog(@"AVPlayerStatusReadyToPlay");
// NSLog(@"Common MetaData %@", self.suraPlayer.currentItem.asset.commonMetadata);
AVAsset * asset = self.suraPlayer.currentItem.asset;
[self metadataForAsset:asset];
} else if (suraPlayer.status == AVPlayerItemStatusUnknown) {
NSLog(@"AVPlayer Unknown");
}
}
}
- (NSString *)titleForAsset:(AVAsset *)asset{
NSArray *titles = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
AVMetadataItem *title;
NSString * currentTitle;
if(titles.count>0)
{
title= [titles objectAtIndex:0];
currentTitle= [title.value copyWithZone:nil];
}
if (self.suraPlayer.currentItem.asset != asset)
asset = nil;
return currentTitle;
}
- (void)metadataForAsset:(AVAsset *)asset{
self.artWorkImage.image = [UIImage imageNamed:@"Colorful-Burst-iPad-wallpaper-ilikewallpaper_com.jpg"];
NSArray *titles = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon];
NSArray *artists = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtist keySpace:AVMetadataKeySpaceCommon];
NSArray *albumNames = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyAlbumName keySpace:AVMetadataKeySpaceCommon];
AVMetadataItem *artist;
AVMetadataItem *title;
AVMetadataItem *albumName;
NSString * currentTitle;
NSString * currentArtist;
NSString * currentAlbumName;
if(titles.count>0)
{
title= [titles objectAtIndex:0];
currentTitle= [title.value copyWithZone:nil];
self.audioTitle.text = currentTitle;
}
if(artists.count>0)
{
artist= [artists objectAtIndex:0];
currentArtist = [artist.value copyWithZone:nil];
}
if (albumNames.count>0){
albumName= [albumNames objectAtIndex:0];
currentAlbumName = [albumName.value copyWithZone:nil];
}
NSArray *keys = [NSArray arrayWithObjects:@"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
for (AVMetadataItem *item in artworks) {
if ([item.keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *d = [item.value copyWithZone:nil];
self.artWorkImage.image = [UIImage imageWithData:[d objectForKey:@"data"]];
} else if ([item.keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
self.artWorkImage.image = [UIImage imageWithData:[item.value copyWithZone:nil]];
}
}
}];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
// code here to play next sound file
if (indexOfSelectedItem<self.filteredAudiosArray.count){
indexOfSelectedItem = indexOfSelectedItem+1;
[self playAudioForFile:[self.filteredAudiosArray objectAtIndex:indexOfSelectedItem]];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:indexOfSelectedItem inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
- (IBAction)sliderValueChangedForDuration:(id)sender {
if ([sender isKindOfClass:[UISlider class]])
{
UISlider* slider = sender;
CMTime playerDuration = self.suraPlayer.currentItem.duration;
if (CMTIME_IS_INVALID(playerDuration)) {
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
float minValue = [slider minimumValue];
float maxValue = [slider maximumValue];
float value = [slider value];
double time = duration * (value - minValue) / (maxValue - minValue);
[self.suraPlayer seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];
}
}
}
Late to the game but in case someone else runs into this, I had this issue because of the way I was setting the time interval to the periodic observer.
Changing to:
CMTime interval = CMTimeMake(33, 1000);
Made things work for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With