I am trying to make an application that use iBeacons to trigger audio when within a certain proximity. In this case it is when in the immediate proximity of the beacon. I have written an if statement that does this the only problem is that the audio file keeps restarting for as long as the device is in that proximity. I want it to trigger only once, play and finish. Not keep triggering over and over again.
The audio to play is defined here.
-(void)playSound
{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/05 Rooster.m4a", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 1;
audioPlayer.currentTime = 0;
audioPlayer.volume = 100.0;
[audioPlayer play];
}
The audio is later called in the if statement
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
beacon = [beacons lastObject];
self.beaconFoundLabel.text = @"In Range";
self.proximityUUIDLabel.text = beacon.proximityUUID.UUIDString;
self.majorLabel.text = [NSString stringWithFormat:@"%@", beacon.major];
self.minorLabel.text = [NSString stringWithFormat:@"%@", beacon.minor];
self.accuracyLabel.text = [NSString stringWithFormat:@"%f", beacon.accuracy];
if (beacon.proximity == CLProximityUnknown) {
self.distanceLabel.text = @"Unknown Proximity";
}
else if (beacon.proximity == CLProximityImmediate)
{
self.distanceLabel.text = @"Immediate";
self.view.backgroundColor = [UIColor greenColor];
_portrait.hidden = YES;
_portraitText.hidden = YES;
_landscape.hidden = NO;
_landscapeText.hidden = NO;
_artworkTitle.text = @"Impression, Sunrise (Impression, soleil levant), 1872";
UIImage *photo = [UIImage imageNamed: @"Sunrise.png"];
[_landscape setImage:photo];
_landscapeText.text = @"Dated 1872, its subject is the harbour of Le Havre in France, using very loose brush strokes that suggest rather than delineate it. Monet explained the title later: \n\nLandscape is nothing but an impression, and an instantaneous one, hence this label that was given us, by the way because of me. I had sent a thing done in Le Havre, from my window, sun in the mist and a few masts of boats sticking up in the foreground.\n\n They asked me for a title for the catalogue, it couldn't really be taken for a view of Le Havre, and I said: 'Put Impression.'";
[self playSound];
}
The other poster's code would let you avoid triggering the sound from playing the same sound multiple times at once. I gather that instead you only want the sound to be played once when you reach a given proximity.
You can adapt Armand's code to do that. Rename the boolean to be "hasPlayed"
Then make your didRange call look something like this:
void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
//Do whatever else you need to do to handle the ranging call
if (!self.hasPlayed)
{
[self playSound];
self.hasPlayed = true;
}
}
Get rid of the custom code in audioPlayerDidFinishPlaying:successfully:
that clears the flag.
If you want to keep track of multiple beacons, and want to play your sound when the user enters the proximity of a different beacon, it's a little more complicated.
If you use the same UUID but a different major value, say, then instead of a boolean, save a unique id of some sort (like the major value) for the last beacon who's sound you've played. Let's call the property lastBeaconRanged. Then when you range a beacon, see if the ranged beacon's ID matches the one who's sound you played last. If not, play the sound and save this beacon's ID into your lastBeaconRanged property.