I am programing an audio player using "AVFoundation.h". I've issues with Updating Progress bar, Hence when I click at play button my app gives error. I am attaching both code samples & error report. can anyone sort this out?
-(void)updateProgress {
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:#"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInt:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInt:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict]; }
When pressed Build & Run app goes successfully started in simulator, I've taken 2 images of active Console
1. before clicking at play button.
After clicking play button. when app goes crash.
enter image description here
now please suggest me what I should do at this point? so that my app start working smoothly...
Thanks
Faiz.
After following instructions by Losiowaty answer last day. those yellow issues are removed but still my programing gives same error when I click at play button.
enter image description here
This time I am uploading complete code and highlighting few things due to which I think error is occurring.
Please take a look at my mainwviewcontroller.m class code.
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize audioPlayer;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error == nil) {
NSLog(#"audio session initialized successfully");
} else {
NSLog(#"error initializing audio session: %#", [error description]);
}
[audioPlayer setDelegate:self];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setFrame:self.airPlayView.bounds];
[self.airPlayView addSubview:volumeView];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
-(void)dealloc
{
[self resignFirstResponder];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
#pragma mark - file picker delegate methods
-(void)cancel
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)didFinishWithFile:(NSString *)filePath
{
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.selectedFilePath = filePath;
NSString *relativeFilePath = [documentsDirectory stringByAppendingPathComponent:filePath];
NSURL *fileURL = [NSURL fileURLWithPath:relativeFilePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
self.audioPlayer.delegate = self;
if (error == nil) {
NSLog(#"audio player initialized successfully");
self.titleLabel.text = self.selectedFilePath;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
NSString *songTitle = [filePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork]];
[infoCenter setNowPlayingInfo:infoDict];
[self play:nil];
} else {
NSLog(#"error initializing audio player: %#", [error description]);
}
//dismiss the file picker
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)play:(id)sender
{
if ([self.audioPlayer isPlaying]) {
[self.audioPlayer pause];
[self.playButton setImage:[UIImage imageNamed:#"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
} else {
[self.audioPlayer play];
[self.playButton setImage:[UIImage imageNamed:#"pause"] forState:UIControlStateNormal];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
animation.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"animation1.png"],
[UIImage imageNamed:#"animation2.png"],
[UIImage imageNamed:#"animation3.png"],nil];
[animation setAnimationRepeatCount:2000];
animation.animationDuration = 0.5;
[animation startAnimating];
}
self.playbackInterrupted = NO;
}
-(IBAction)skipForward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime + 15.0f;
if (desiredTime < self.audioPlayer.duration) {
self.audioPlayer.currentTime = desiredTime;
}
}
}
-(IBAction)skipBackward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime - 15.0f;
if (desiredTime < 0) {
self.audioPlayer.currentTime = 0.0f;
} else {
self.audioPlayer.currentTime = desiredTime;
}
}
}
#pragma mark - Timer delegate
-(void)updateProgress
{
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:#"%ld:%02ld / %ld:%02ld", currentTimeMinutes,currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInteger:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInteger:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict];
}
#pragma mark - AVAudioPlayer delegate methods
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag) {
[self.playButton setImage:[UIImage imageNamed:#"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
}
}
#pragma mark - Remote control
-(void)remoteControlReceivedWithEvent:(UIEvent *)event
{
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
case UIEventSubtypeRemoteControlPause:
case UIEventSubtypeRemoteControlTogglePlayPause:
[self play:nil];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self skipForward:nil];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self skipBackward:nil];
break;
default:
break;
}
}
#pragma mark - audio interruption
-(void)caughtInterruption:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *type =[userInfo objectForKey:AVAudioSessionInterruptionTypeKey];
if ([type integerValue] == AVAudioSessionInterruptionTypeBegan) {
if (self.audioPlayer.playing) {
[self.audioPlayer pause];
[animation stopAnimating];
self.playbackInterrupted = YES;
}
} else {
if (self.audioPlayer.playing == NO && self.playbackInterrupted == YES) {
[self.audioPlayer play];
[animation startAnimating];
self.playbackInterrupted = NO;
}
}
}
#pragma mark - route changed
-(void)routeChanged:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *reason =[userInfo objectForKey:AVAudioSessionRouteChangeReasonKey];
switch ([reason integerValue]) {
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
[self.audioPlayer stop];
[animation stopAnimating];
break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
case AVAudioSessionRouteChangeReasonWakeFromSleep:
[self.audioPlayer pause];
[animation stopAnimating];
break;
default:
break;
}
}
#end
above code is error free & pretty clean, everything is clearly mentioned, I am using 4 buttons,
for Play & Pause
for seeking forward
for seeking backward
for entering into document directory for audio file picking
when I am pressing this fourth button it prepares for entering into another view for picking audio file.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
I needs two things to accomplish
the first things which I needs to accomplish is that,
I don't wants to enter into next view, because I am testing my app into simulator where there is no physical audio file I can place or locate in simulator, hence I needs to avoid this thing just for my owns testing purpose.
Hence I am willing to add an audio mp3 file into NSBundle and wants to play this file when I press play button file starts playing & then Pause when pressing again. code for paying & pause is pretty clean working well. but for initializing file path is I think I've to initialize file path in viewDidload method by replacing above view did load by following code.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"Nameofflie" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
NSError *error = nil;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
if (error == nil) {
NSLog(#"audio session initialized successfully");
} else {
NSLog(#"error initializing audio session: %#", [error description]);
}
[audioPlayer setDelegate:self];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setFrame:self.airPlayView.bounds];
[self.airPlayView addSubview:volumeView];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
}
this code also Runs & compiles pretty well but when pressing play button same error occurring. so please suggest me where to place following lines to play MP3 Music file placed from NSBudle .
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"rabne" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
this point is totally different from just above point number 1 which I am willing to accomplish. when after testing successfully, playing that NSBundle audio MP3 file.
I wants to work with my earlier code again, as the end user is not using my simulator, hence for end users I wants to have same option which already I accomplished in above Mainviewcontroller.m class,i.e. user have to press 4th number button for accessing their device's document directory file path. that works pretty well in my code. but the thing here I wants to point to or needs to sort out is that, if someone directly pressing very 1st play button without pressing 4th button for going & selecting an audio file, an alert view should appear with a message that first select a file by pressing fourth button and then click play button. That's it I am willing to have in my code.
Based on the exception in screenshot #2, it looks that you are trying to insert a nil object into an array. The only place where you insert some objects into array is this line :
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
The second array, the one with the keys, looks ok, as it consisits of only system provided consts. The first one on the other hand has two objects than could be nil : songTitle and albumArt.
The reasons for these to be nil are :
songTitle may be nil if self.selectedFilePath is nil
albumArt - I'm not entirely sure, but it could end up being nil if your image was not found.
Please make sure that these two are not nil and everything should be working fine.
As to your warnings, these two :
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInt:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInt:durationSeconds];
can be fixed by changing to [NSNumber numberWithInteger:] and are caused by the fact that NSInteger is a typedef for long and not int.
The warning on
NSString *progressString = [NSString stringWithFormat:#"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
is caused by virtually the same thing. %d expects an int, and NSInteger is a long. Changing %d to %ld will fix it.
It is still my firm belief that these didn't cause the crash, especially based on the thrown exception which is pretty straightforward in stating what has happend.
The provided code confirms my assumptions - the crash happens because self.selectedFilePath is nil in updateProgress method resulting in songTitle also being nil. Why this happens? The only place in provided code where you set self.selectedFilePath is in didFinishWithFile: method, which I assume is a delegate method of FileViewController. If you don't present it and selected something there, that method is not called.
Now, if you want to setup this for testing, the easiest way would be to add this in your viewDidLoad :
NSError *error;
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"rabne" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
if (error == nil) {
self.selectedFilePath = #"test file"; // <<-- IMPORTANT
self.titleLabel.text = self.selectedFilePath;
} else {
NSLog(#"error initializing audio player: %#", [error description]);
}
just above [audioPlayer setDelegate:self];. This should get everything going.
On a side note : I'd also remove this line self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES]; from didFinishWithFile: method - you also setup a timer in play: method, and it seems safer to do it once.
As to point #2 - I can give you a hint, that you know if a file is selected when self.selectedFilePath != nil and to take a look at UIAlertViewController class. The rest of work is left for you, as it was not a part of the original problem and has nothing to do with solving the crash. Also, you wouldn't learn anything that way :)
I have to automatic stop the player at second X and I don't know which kind of notification I have to used.
After, when user taps anywhere on the screen the player continue to run the video.
- (IBAction)playMovie:(id)sender {
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"movie" ofType:#"m4v"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
_moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:_moviePlayer];
//here I don't know which notification I have to used
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackPause:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:_moviePlayer];
_moviePlayer.controlStyle = MPMovieControlStyleDefault;
_moviePlayer.initialPlaybackTime = 2.5;
_moviePlayer.shouldAutoplay = YES;
[self.view addSubview:_moviePlayer.view];
[_moviePlayer setFullscreen:YES animated:NO];
[_moviePlayer play];
}
I tried to catch the movie frame and analyzed it to see if is time to pause the video.
- (void) moviePlayBackPause:(NSNotification*)notification{
// check if it's time to pause the video
if([_moviePlayer currentPlaybackTime] == 6.0){
[_moviePlayer pause];
}
}
Which type of notification I have to use to catch the current time of the video?
Thanks in advance for all your responses!
Kind regards!
You can use a NSTimer to stop your video.
Should exist a better way to do it, but with timer you can do it as well.
[_moviePlayer play];
[NSTimer scheduledTimerWithTimeInterval:6 //Time in seconds
target:self
selector:#selector(moviePlayBackPause) //Method called when the timer is completed.
userInfo:nil
repeats:NO];
}
}
- (void) moviePlayBackPause {
[_moviePlayer pause];
}
I was Created AVAudio Player, its playing perfectly,Click the play button song is playing and its shows pause button,click pause button song is paused and its shows play button,but click the play button is playing from starting onwards.i want play resume song. how to control this issue. this is my code , please check once's.
-(void)playAudio
{
// [progreetimer invalidate];
// if([audioPlayer isPlaying]==YES)`enter code here`
if(self.isPlaying)
{
[self.play setBackgroundImage:[UIImage imageNamed:#"audioplayer_play.png"]
forState:UIControlStateNormal];
NSLog(#"Pausing Music");
if (self.progreetimer) {
[self.progreetimer invalidate];
progreetimer =nil;
}
[audioPlayer pause];
self.isPlaying = NO;
}
else {
// Init audio with playback capability
[self.play setBackgroundImage:[UIImage imageNamed:#"audioplayer_pause.png"] forState:UIControlStateNormal];
// NSString *urlstr = #"http://jesusredeems.in/media/Media Advt/mp3_player/Songs/viduthalaiyin geethangal_vol1/93.Ellame Koodum.mp3";
NSString *urlstr =#"http://www.abstractpath.com/files/audiosamples/sample.mp3";
urlstr = [urlstr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlstr];
NSData *data = [NSData dataWithContentsOfURL:url];
audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
audioPlayer.volume = 1.9f;
// [audioPlayer prepareToPlay];
SongProgressBar.maximumValue = [audioPlayer duration];
SongProgressBar.value = 0.0;
NSLog(#"Playing music");
//start a timer to update the time label display
self.progreetimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(updateTime:) userInfo:nil repeats:YES];
self.progreetimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(updateSlider) userInfo:nil repeats:YES];
[progreetimer fire];
audioPlayer.delegate=self;
[audioPlayer play];
self.isPlaying = YES;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.SongProgressBar.minimumValue = 30;
self.SongProgressBar.maximumValue = 30;
[self.SongProgressBar setThumbImage:[UIImage imageNamed:#"thumbslider.png"]
forState:UIControlStateNormal];
// [self.SongProgressBar setThumbImage:[UIImage imageNamed:#"slider_icon.png"]
// forState:UIControlStateHighlighted];
[self.SongProgressBar setMinimumTrackImage:[UIImage imageNamed:#"slider_max.png"]
forState:UIControlStateNormal];
[self.SongProgressBar setMaximumTrackImage:[UIImage imageNamed:#"slider_icon.png"]
forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[audioPlayer pause]; // Or pause
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[audioPlayer play];
}
- (IBAction)songprogressbar:(id)sender {
// Fast skip the music when user scroll the UISlider
[audioPlayer stop];
[audioPlayer setCurrentTime:SongProgressBar.value];
[audioPlayer prepareToPlay];
[audioPlayer play];
}
- (IBAction)backword:(id)sender {
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = audioPlayer.currentTime -15.0f;
if (desiredTime < 0) {
audioPlayer.currentTime =0.0f;
} else {
audioPlayer.currentTime = desiredTime;
}
}
}
- (IBAction)play:(id)sender {
[self playAudio];
}
- (void)updateSlider {
// Update the slider about the music time
SongProgressBar.value = audioPlayer.currentTime;
}
- (void)setCurrentAudioTime:(float)value {
[self.audioPlayer setCurrentTime:value];
}
//Stops the timer when the music is finished
- (void)audioPlayerDidFinishPlaying : (AVAudioPlayer *)player successfully : (BOOL)flag {
// Music completed
if (flag) {
[progreetimer invalidate];
NSLog(#"Finished playing the song");
}
}
- (IBAction)forword:(id)sender {
if ([audioPlayer isPlaying]) {
NSTimeInterval desiredTime = audioPlayer.currentTime +15.0f;
if (desiredTime < audioPlayer.duration) {
audioPlayer.currentTime = desiredTime;
}
}
}
- (IBAction)volume:(id)sender {
audioPlayer.volume=volume.value;
}
-(NSString*)timeFormat:(float)value{
float minutes = floor(lroundf(value)/60);
float seconds = lroundf((value) - (minutes * 60));
int roundedSeconds = lroundf(seconds);
int roundedMinutes = lroundf(minutes);
NSString *time = [[NSString alloc]
initWithFormat:#"%d:%02d",
roundedMinutes, roundedSeconds];
return time;
}
- (void)updateTime:(NSTimer *)timer {
self.starttimer.text = [NSString stringWithFormat:#"%#",
[self timeFormat: ceilf(audioPlayer.currentTime)]];
self.endtimer.text = [NSString stringWithFormat:#"-%#", [self timeFormat: (audioPlayer.duration - ceilf(audioPlayer.currentTime))]];
}
You should try this. see else part of method
-(void)playAudio
{
// [progreetimer invalidate];
// if([audioPlayer isPlaying]==YES)`enter code here`
if(self.isPlaying)
{
//Code to pause audioPlayer
[audioPlayer pause];
self.isPlaying = NO;
}
else
{
if(audioPlayer.url != nil && audioPlayer.duration != 0)
{
[audioPlayer play];
}
else
{
//Code to add new audioPlayer
}
}
}
Use the following code
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
[player prepareToPlay];
player.currentTime = 0;
[player play];
My basic problem is that I cannot seem to work out how to bring the Activity indicator to the top so I can show that a process is running while new data is populating the UITableView. To load new data I am using a Segmented Control. When segment 0 is pressed it will load the first xml feed and when segment 1 is pressed it will load a second xml feed. I have tried using dispatch_queue_t etc. it does load the information and repopulate the table, it just doesn't show the indicator.
This is the code i am currently using.
if (Seg.selectedSegmentIndex == 0) {
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[tableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else if (Seg.selectedSegmentIndex ==1){
// tableView = [[UITableView alloc]init];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kMonthsReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[tableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
Thanks in advance.
EDIT:Relevant code
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
[ActInd stopAnimating];
[UiTableView reloadData];
});
});
}
-(void)handleUpdate:(NSNotification*)notification{
mainArray = [xml parsedArray];
[UiTableView reloadData];
}
-(void)loading{
if (![xml val]) {
[ActInd startAnimating];
}else
{
[ActInd stopAnimating];
[UiTableView reloadData];
}
}
-(IBAction)segvalueChange:(id)sender{
if (Seg.selectedSegmentIndex == 0) {
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kTodaysReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else if (Seg.selectedSegmentIndex ==1){
// UiTableView = [[UITableView alloc]init];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
dispatch_queue_t loader = dispatch_queue_create("a", NULL);
dispatch_async(loader, ^{
xml = [[XmlParser alloc]init];
url = [NSURL URLWithString:kMonthsReport];
dict = [[NSMutableDictionary alloc]init];
[xml loadXML:url];
[UiTableView addSubview:ActInd];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(handleUpdate:) name:#"update" object:nil];
});
});
}
else{
}
}
The problem is that you are interacting with the UI on a background thread. Move all UI related code (including that which interacts with the activity view) into the GCD block for the main thread.
Im using AVQueuePlayer to loop through an array of AVPlayerItems.
The way I'm looping it, I listen to the AVPlayerItemDidPlayToEndTimeNotification and every time its called, I add the current object to the end of the queue.
heres the code:
viewWillAppear
{
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_queuePlayer currentItem]];
[_queuePlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNew = [[AVPlayerItem alloc] initWithAsset:p.asset];
if (_queuePlayer.items.count == 1)
{
[p seekToTime:kCMTimeZero];
[_queuePlayer play];
}
else
{
[_queuePlayer insertItem:fakeNew afterItem:[_queuePlayer.items lastObject]];
}
NSLog(#"array of items to play:%lu", (unsigned long)_queuePlayer.items.count);
}
The problem is, that the method is called only for the first video that plays, after that, the method stops getting called, so if for example i have 2 movies in the array, it would play them both+the first one again, any idea why is this happening?
More Info:
also tried to make a new player every time and set it to layer. failed to send the notification more than once just the same
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:p];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[_player play];
}
After a lot of messing around, apparently for whatever reason, the view unregistered as observer every time, I just removed and added observer after every notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNewItem = [[AVPlayerItem alloc] initWithAsset:p.asset];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:fakeNewItem];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_player currentItem]];
[_player play];
}
For a clean approach to resolve this issue. I approached with the next piece of code instead
The first is you have to add the code necessary to receive a feedback from the AVPlayer when the reproduction time changes.
- (void)addPeriodicTimeObserverForReproductionChanges {
#weakify(self);
[self.player
addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(kBQDefaultTimeIntervalReproductionChanges, NSEC_PER_SEC)
queue:self.eventsQueue
usingBlock:^(CMTime time) {
#strongify(self);
[self dispatchBlockOnMainQueue:^{
if ([self.delegate respondsToSelector:#selector(playerItemController:didChangeReproductionTime:)])
[self.delegate playerItemController:self
didChangeReproductionTime:time];
[self checkForItemPlayToEnd];
}];
}];
}
- (void)checkForItemPlayToEnd
{
CMTime durationScaled = CMTimeConvertScale(self.duration,self.player.currentTime.timescale, kCMTimeRoundingMethod_Default);
if (CMTIME_COMPARE_INLINE(durationScaled, ==, self.player.currentTime)) {
[self playerDidFinishReproducingItem];
}
}