Is it possible to force an audio file to finish playing before proceeding with code? In the below example, I'd like an audio file to play for as many times as I have items in the array. current it finishes the loop only playing once. I'm using the AVAudioPlayer within the AVFoundation framework.
for (int i = 0; i<[Array count]; i++) {
if ([Array objectAtIndex:i] == #"Red") {
NSLog(#"red");
[self.player play];
}
if ([Array objectAtIndex:i] == #"Blue") {
NSLog(#"blue");
[self.player play];
}
if ([Array objectAtIndex:i] == #"Green") {
NSLog(#"green");
[self.player play];
}
if ([Array objectAtIndex:i] == #"Yellow") {
NSLog(#"yellow");
[self.player play];
}
}
I also use the method audioPlayerDidFinishPlaying to test if it's finishing five times, but it only reaches this method once.
-(void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL) completed{
if ((completed) == YES){
NSLog(#"audio finish");
return;
}
}
Is it possible to hold the for loop in place while the audio is playing?
in theory the console should read: color->audio finish->color->audio finish->repe
Maybe you can tell the AudioPlayer to play when you receive the finishedPlaying notification like:
int arrayIndex = 0
NSArray* array; //initialized somewhere..
-(void)myFunction
{
if(arrayIndex < [array length])
{
NSArray* colors = [NSArray arrayWithObjects:#"Red",#"Blue",#"Green",#"Yellow",nil];
if( [colors indexOf:[array objectAtIndex:arrayIndex]] != NSNotFound )
{
NSLog( [array objectAtIndex:arrayIndex] );
[self.player play];
}
arrayIndex++;
}else{
NSLog(#"audio finish");
}
}
-(void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL) completed{
if ((completed) == YES){
[self myFunction];
}
}
-(void)start_it_up
{
arrayIndex = 0;
[self myFunction];
}
Related
I’m trying to make a custom matchmakingview using a matchmaker. The code below is used to find a match.
When i run this on two different devices with different Game Center accounts, both will get a match but none will connect to the match. They will just get stuck in the while loop in infinity and never get out. Have i missed something, do you need to call something to actually connect to the match?
- (void) findMatch{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = nil;
NSLog(#"Start searching!");
[matchmaker findMatchForRequest:request
withCompletionHandler:^(GKMatch *match, NSError *error)
{
if (error) {
// Print the error
NSLog(#"%#", error.localizedDescription);
}
else if (match != nil)
{
curMatch = match;
curMatch.delegate = self;
NSLog(#"Expected: %i", match.expectedPlayerCount);
while (match.expectedPlayerCount != 0){
NSLog(#"PLayers: %i", curMatch.playerIDs.count);
}
NSLog(#"Start match!");
}
}];
You should not be using a while loop to wait for expectedPlayerCount to reach 0, instead implement the GKMatchDelegate method:
- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
if (!self.matchStarted && match.expectedPlayerCount == 0) {
self.matchStarted = YES;
//Now you should start your match.
}
}
I am building a AVQeueue Player from a set of encoded videos on an s3 bucket, playing videos in sequence using AVPlayerActionAtItemEndAdvance;
videos are all encoded the same resolution and codec
They are all tested good to play
On some devices this solution below works fine
The issue below is noticed both on IOS 5.x and 6.x
Been trying to check all done in the main thread. (most likely the issue)
Issue: on the simulator and on some devices (noticed on 4s and 5) after an x amount of videos (x being unpredictable at times but usually 3, 4) a video plays only with sound and kills the queue and does not throw "playerItemDidReachEnd" notification. App does not crash or freeze.
No Errors received from "AVPlayerItemStatusFailed" or "AVPlayerItemStatusUnknown"
If anyone has experience with this problem please share.
Code:
-(void)addObservers {
dispatch_async(dispatch_get_main_queue(),
^{
for(int i = 0; i < [self.videodata count]; i++) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.videodata objectAtIndex:i]];
[[self.videodata objectAtIndex:i] addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[[self.videodata objectAtIndex:i] addObserver:self forKeyPath:#"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[[self.videodata objectAtIndex:i] addObserver:self forKeyPath:#"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
}
});
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *) change context:(void *)context
{
if ([object isKindOfClass:[AVPlayerItem class]])
{
AVPlayerItem *item = (AVPlayerItem *)object;
if ([keyPath isEqualToString:#"status"])
{ //yes->check it...
switch(item.status)
{
case AVPlayerItemStatusFailed:
{
[TestFlight passCheckpoint:#"AV FAILED"];
NSError *error = [item error];
NSLog(#"playback error is %#", error);
break;
}
case AVPlayerItemStatusReadyToPlay:
NSLog(#"player item status is ready to play");
break;
case AVPlayerItemStatusUnknown:
{
[TestFlight passCheckpoint:#"AV STATUS UNKNOWN"];
break;
}
}
}
else if (item == [self.queuePlayer currentItem] && [keyPath isEqualToString:#"playbackBufferEmpty"])
{
if (item.playbackBufferEmpty)
{
[loadingView show:YES];
}
}
else if(item == [self.queuePlayer currentItem] && [keyPath isEqualToString:#"playbackLikelyToKeepUp"])
{
[self.queuePlayer play];
[loadingView hide:YES];
}
}
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
NSLog(#"ended video %i " , (int)self.currentItem);
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}
I have built objectives for my game and everything works just fine accept the part of making the objectives not be called any more after any of them is completed.
I know there is a Property of the GKAchievement Class "completed" which is a boolean that returns yes when the Achievement is 100 percent done.
here is the method that called when a Achievement is 100 percent done it passes id which is the Achievement identifier and report the acheeee :
- (void)AchivmentDidAchive:(id)Achivment{
NSString *identifier = Achivment;
NSLog(#"%#",identifier);
self.achivment = [[GKAchievement alloc]initWithIdentifier:identifier];
self.achivment.showsCompletionBanner = YES;
if (!self.achivment.completed) {
self.achivment.percentComplete = 100;
NSLog(#"Reproting!");
[self.achivment reportAchievementWithCompletionHandler: ^(NSError *error)
{
}];
}
else {
NSLog(#"Achivment Completed!");
} }
what I am trying to do here is to set the percent completed to 100 and report it so in the next time ie want get called again.
but it always works... any better idea for how to handle this?
in interface add variable & property:
NSMutableDictionary *earnedAchievementCache;
#property (nonatomic, retain)NSMutableDictionary *earnedAchievementCache;
in .m:
#synthesize earnedAchievementCache;
- (void) submitAchievement: (NSString*) identifier percentComplete: (double) percentComplete
{
if(self.earnedAchievementCache == NULL)
{
[GKAchievement loadAchievementsWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
if(error == NULL)
{
NSMutableDictionary* tempCache= [NSMutableDictionary dictionaryWithCapacity: [scores count]];
for (GKAchievement* score in scores)
{
[tempCache setObject: score forKey: score.identifier];
}
self.earnedAchievementCache= tempCache;
[self submitAchievement: identifier percentComplete: percentComplete];
}
}];
}
else
{
GKAchievement* achievement= [self.earnedAchievementCache objectForKey: identifier];
if(achievement != NULL)
{
if((achievement.percentComplete >= 100.0) || (achievement.percentComplete >= percentComplete))
{
achievement= NULL;
}
achievement.percentComplete= percentComplete;
}
else
{
achievement= [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
achievement.percentComplete= percentComplete;
[self.earnedAchievementCache setObject: achievement forKey: achievement.identifier];
}
if(achievement!= NULL)
{
//Submit the Achievement...
if (achievement.percentComplete>=100) {
//show banner
achievement.showsCompletionBanner = YES; //only in IOS 5+
}
[achievement reportAchievementWithCompletionHandler: ^(NSError *error)
{
if (error!=NULL){
NSLog(#"Error!!");
} else NSLog(#"all is well");
}];
}
}
}
in dealloc :
[self.earnedAchievementCache release];
i'm using the cache to not submit scores already submitted / completed
PS: the code is perfect just copy and paste it into your class and it will work
this is what I use in my helper Game Center class:
-(void) reportAchievementWithID:(NSString*) AchievementID {
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
if(error) NSLog(#"error");
for (GKAchievement *ach in achievements) {
if([ach.identifier isEqualToString:AchievementID]) { //already submitted
NSLog(#"Already submitted");
return ;
}
}
GKAchievement *achievementToSend = [[GKAchievement alloc] initWithIdentifier:AchievementID];
achievementToSend.percentComplete = 100;
achievementToSend.showsCompletionBanner = YES;
[achievementToSend reportAchievementWithCompletionHandler:NULL];
}];
}
note: I don't use percentages in my achievements, so you'd need to modify things a little bit if you do.
Here is the code for next and previous button
- (IBAction)nextPressed:(id)sender
{
Previousbutton.enabled=YES;
Nextbutton.enabled = NO;
NSLog(#"TOTAL TRACK:%d",TotalTrackCount);
// TrackCount = TotalTrackCount+1;
if(selectedIndex+1 < TotalTrackCount)
{
[streamer stop];
[self performSelector:#selector(destroyStreamer) ] ;
//player flag
player=#"stop";
int new_index;
new_index=selectedIndex+1;
selectedIndex=new_index;
str_AudioUrl=[array_audioUrl objectAtIndex:selectedIndex];
userPrefs = [NSUserDefaults standardUserDefaults];
[userPrefs setInteger:new_index forKey:#"Index"];
str_AudioUrl=[array_audioUrl objectAtIndex:new_index];
[self performSelector:#selector(createStreamer) ] ;
//[self setButtonImage:[UIImage imageNamed:#"loadingbutton.png"]];
[streamer start];
NSString *newtitle=[array_AudioName objectAtIndex:new_index];
self.title=newtitle;
NSLog(#"selected index next==%d",selectedIndex);
[self performSelector:#selector(enableNext) withObject:nil afterDelay:2.0];
}
else {
Nextbutton.enabled=NO;
}
}
- (void) enableNext
{
Nextbutton.enabled = YES;
}
//it will play next sone from table (next index)
- (IBAction)previousPressed:(id)sender
{
Nextbutton.enabled = YES;
Previousbutton.enabled = NO;
NSLog(#"selected index previous==%d",selectedIndex);
if(selectedIndex >0)
{
[streamer stop];
//player flag
player=#"stop";
[self performSelector:#selector(destroyStreamer) ] ;
int new_index;
new_index=selectedIndex-1;
selectedIndex=new_index;
str_AudioUrl=[array_audioUrl objectAtIndex:selectedIndex];
userPrefs = [NSUserDefaults standardUserDefaults];
[userPrefs setInteger:new_index forKey:#"Index"];
str_AudioUrl=[array_audioUrl objectAtIndex:new_index];
[self performSelector:#selector(createStreamer)] ;
[self setButtonImage:[UIImage imageNamed:#"loadingbutton.png"]];
[streamer start];
NSLog(#"selected index previous2==%d",selectedIndex);
NSString *newtitle=[array_AudioName objectAtIndex:new_index];
self.title=newtitle;
[self performSelector:#selector(enablePrevious) withObject:nil afterDelay:2.0];
}
else {
Previousbutton.enabled = NO;
}
}
- (void) enablePrevious
{
Previousbutton.enabled = YES;
}
AudioStreamer class has a bug related to Pause during streaming. So a nice post is given on gitHub to solve this problem.
I am developing an application which upload number of photos and xml file in one attempt. I have two core data table with one-many(jobs & photos) relation. One job may contain number of photos. Once all the photos has uploaded I need to upload xml file which contain photos details. I need to keep track on which photo has upload successfully and update the jobs table's status field as well as photo status. Following code illustrate that.
This works some time. Some time this is not updating jobs table. I do appreciate is anyone can let me know what is wrong with following code.
NSMutableArray *photosForJob=[[NSMutableArray alloc] initWithArray:[fetchedJob.photos allObjects]];
self.manageObjectForJobs = fetchedJob;
__block int count = 0;
dispatch_group_async(group, queue, ^{
for (int i = 0; i < [photosForJob count]; i++)
{
Photos *ph = [photosForJob objectAtIndex:i];
if ([ph.status compare:[NSNumber numberWithBool:NO]] == NSOrderedSame)
{
NSMutableArray *responseArray = [self filePosting:ph.photoName];
self.manageObjectForPhotos = ph;
if ([[responseArray objectAtIndex:0] isEqual:#"200"] && [[responseArray objectAtIndex:1] isEqualToString:ph.photoName])
{
[self.manageObjectForPhotos setValue:[NSNumber numberWithBool:YES] forKey:#"status"];
count++;
}
}
else{
count++;
}
}
if (count == [photosForJob count])
{
if ([status compare:[NSNumber numberWithBool:NO]] == NSOrderedSame)
{
NSMutableArray *responseArray = [self filePosting:xmlFile];
if ([[responseArray objectAtIndex:0] isEqual:#"200"] && [[responseArray objectAtIndex:1] isEqualToString:xmlFile]){
[self.manageObjectForJobs setValue:[NSNumber numberWithBool:YES] forKey:#"status"];
}
}
}
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Job status did updat.... : %#", [error description]);
}
else{
[UIApplication sharedApplication].applicationIconBadgeNumber = [self fetchJobsForBadge];
[photosForJob removeAllObjects];
count = 0;
}
});
Many Thanks