How to select and play different audio files with AVAudioPlayer - ios

I am currently using AVAudioPlayer to play an MP3 file when the method is triggered.
This works well however I would now like to add in the ability to select which audio file is played when the method is triggered from a list, this is not going so well.
I have created a UISegmentedControl and attempted to change the AVAudioPlayer method to reflect what has been selected however I am now receiving the following error when the app is launched:
'NSInvalidArgumentException', reason: '*** -[NSURL
initFileURLWithPath:]: nil string parameter'
From what I understand, I am recieving the above error because when the AVAudioPlayer is attempting to initWithContentsOfUrl:, the string being referenced does not contain any data yet, I thought it may have got this from the default segment in the UISegmentedController, however this is not the case.
I have searched for a solution for this but could not find anything which matched what i was attempting to achieve, the closest I could find was to initiate a new session of AVAudioPlayer for every audio file I wanted to play however this seemed very long winded and ultimatly may still not work.
Below is my code so far, if you could suggest how I could make this work, I would appreciate it.
for the UISegmentedController:
- (void) selectTone:(id)sender
{
if (self.alarmToneType == 0) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"alarm" ofType: #"mp3"];
NSLog(#"Tone Selected 0 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
if (self.alarmToneType == 1) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"redalert" ofType: #"mp3"];
NSLog(#"Tone Selected 1 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
if (self.alarmToneType == 2) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"greenalaert" ofType: #"mp3"];
NSLog(#"Tone Selected 2 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
}
I have created the string as a #property above but didn't think you would need that.
for the AVAudioPlayer:
- (void) setupAppAudio {
/////////////////////////////////////////////////////////////////////////////////////
// SOUNDS
// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setActive:YES error:nil];
// Use this code instead to allow the app sound to continue to play when the screen is locked.
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &sessionError];
if (sessionError) {
NSLog(#"AVAudioSession ERROR %#", sessionError);
} else {
NSLog(#"AVAudioSession SUCCESSFUL");
}
// Tell other music to be quiet when we are talking!
UInt32 doSetProperty = 1;
AudioSessionSetProperty (kAudioSessionProperty_OtherMixableAudioShouldDuck,
sizeof (doSetProperty),
&doSetProperty);
// Registers the audio route change listener callback function
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
(__bridge void *)(self));
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
// setup
//NSString *filePath;
AVAudioPlayer *newPlayer;
newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:self.filePath] error: nil];
self.beepPlayer = newPlayer;
// "Preparing to play" attaches to the audio hardware and ensures that playback
// starts quickly when the user taps Play
[self.beepPlayer prepareToPlay];
[self.beepPlayer setVolume: 1.0];
[self.beepPlayer setDelegate: self];
}

Related

Sound Not Playing after updating to ARC Obj-c

I recently updated my project with Automatic Reference Counting (ARC) and it broke my playAudio methods (worked perfect before). I am new to ARC but am pretty certain it is due to the retain count or the system releasing the object immediately so you never hear the sound play at all. I create a iVar of the AudioPlayer and try to keep my own personal retain count as found in question linked below. I call out the playSystemSound: from another class, by first alloc]init; then [class playSystemSound:1002]; If anyone can point out what it is I am doing wrong that would be greatly appreciated.
AVAudioPlayer not playing any sound
#property (strong, nonatomic) AVAudioPlayer *soundToPlay;
-(void)playsystemSound:(long long)eventType{
NSString *path = [NSString stringWithFormat:#"/User/Library/Preferences/com.idd.iconomaticprefs.plist"];
NSMutableDictionary* savedDict = [NSMutableDictionary dictionary];
[savedDict addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:path]];
NSMutableArray *activeThemesArray = [savedDict valueForKey:#"ActiveThemes"];
if ([activeThemesArray count]) {
NSString *soundURL;
for (NSString *name in activeThemesArray) {
soundURL = [NSString stringWithFormat:#"/Library/Themes/%#/UISounds",name];
if ([[NSFileManager defaultManager]fileExistsAtPath:soundURL]) {
//UISounds avilable in theme determine event type
if (eventType == 1002) {
//respring?
soundURL = [NSString stringWithFormat:#"/Library/Themes/%#/UISounds/lock.caf",name];
}
if (eventType == 1003) {
soundURL = [NSString stringWithFormat:#"/Library/Themes/%#/UISounds/Anticipate.caf",name];
}
if (eventType == 1004) {
soundURL = [NSString stringWithFormat:#"/Library/Themes/%#/UISounds/key_press_click.caf",name];
}
if (eventType == 1008) {
soundURL = [NSString stringWithFormat:#"/Library/Themes/%#/UISounds/photoShutter.caf",name];
}
// setup session correctly
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audiosession setActive:YES error:nil];
// play sound
NSURL *url = [NSURL fileURLWithPath:soundURL];
self.soundToPlay = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[self.soundToPlay prepareToPlay];
[self.soundToPlay play];
break;
}
}
}
}
If there is no strong reference keeping hold of it, your AudioSession will go away as soon as the method returns.

AVAudioPlayer looped sound oddities

I'm using this code to load and begin playing a sound:
- (void) buzz {
if (buzzSound == nil) {
[[AVAudioSession sharedInstance] setActive: YES error: nil];
NSError *error;
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *soundFile = [[NSURL alloc] initFileURLWithPath: [mainBundle pathForResource: #"buzzer_8"
ofType: #"wav"]];
buzzSound = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFile error: &error];
buzzSound.delegate = self;
if (DEBUG_BLE && error != nil)
printf("Error loading sound: %s\n", [[error localizedDescription] cStringUsingEncoding: NSUTF8StringEncoding]);
}
// Play the sound.
buzzSound.numberOfLoops = -1;
[buzzSound prepareToPlay];
[buzzSound setVolume: 1.0];
if (![buzzSound play]) {
self.buzzSound = nil;
[self buzzSound];
}
}
This code is triggered by a touch down event on a button. When the button gets a touch up event (on or off of the button), it stops the sound with:
[buzzSound stop];
The buzz sound itself is a short .wav file.
The first time buzz is called, the sound plays once. It does not repeat. On subsequent calls it does repeat. Why?
Intermittently, if I play the sound for a short period of time that is about the same length of time as one cycle through the sound file, the sound fails on subsequent calls to buzz, and play returns NO. Thereafter, play will always return NO until the sound is reloaded, after which is plays the sound once as noted above and then starts working correctly until the sound is played for a short time, again.
I do have audioPlayerDecodeErrorDidOccur:error: set up; no error is reported.

Error with AVAudio Player in an SKScene

I am trying to make a background music in my game with AVAudioPlayer, so I set this code at the initWithSize method of my SKScene:
//SETTING BACKGROUND MUSIC//
NSError * err = nil;
NSURL * musicFile = [[NSBundle mainBundle] URLForResource:#"Cosmic Rush" withExtension:#"m4a"];
music = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&err];
if(err)
{
NSLog(#"%#", [err userInfo]);
return;
}
[music prepareToPlay];
music.numberOfLoops = -1;
[music setVolume:0.5];
//SETTING BACKGROUND MUSIC//
Then, in another method: [music play]; However, the sound never plays, and I have tried all sort of extensions: .mp3, .caf, .mp4 etc. I have also checked people who had the same problem, but none of the solutions that solved their problems worked with mine.
there is a easier way to add background music to your scene. i use the following steps and works just as good as any other methods and it is easier.
import the #import AVFoundation; at the top of your scene.
add it as a property right after your #implementation.
AVAudioPlayer *_backgroundMusicPlayer;
then declare a method for the music
- (void)playBackgroundMusic:(NSString *)filename
{
NSError *error;
NSURL *backgroundMusicURL =
[[NSBundle mainBundle] URLForResource:filename
withExtension:nil];
_backgroundMusicPlayer =
[[AVAudioPlayer alloc]
initWithContentsOfURL:backgroundMusicURL error:&error];
_backgroundMusicPlayer.numberOfLoops = -1;
[_backgroundMusicPlayer prepareToPlay];
[_backgroundMusicPlayer play];
}
after that create a reference to that method in your -(id)initWithSize:(CGSize)size like the following
[self playBackgroundMusic:#"bgMusic.mp3"];
that should take care of the background music for you.

AVAudioPlayer initWithContentsOfURL returns nil for AAC/M4A files

I use the following code to play an audio file. It plays fine for MP3 files, but when I try to play an AAC file, the [[AVAudioPlayer alloc] initWithContentsOfURL:] returns nil and I get the following error:
Error Domain=NSOSStatusErrorDomain Code=1937337955 "The operation couldn’t be completed. (OSStatus error 1937337955.)"
The audio file plays fine on Mac and iPhone (when I email it to myself) and is here: https://dl.dropboxusercontent.com/u/2667666/song.aac
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
// Create audio player with background music
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:#"song" ofType:#"aac"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
if (!_backgroundMusicPlayer) {
NSLog(#"_backgroundMusicPlayer pointer is null!!");
}
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer prepareToPlay];
[_backgroundMusicPlayer play];
Update: If I change the extension of the file from aac to m4a, the error code change to 1954115647 (whose four letter code is "tip?"). The four letter code for the error code that I get with the arc extension is "sync".
Initializing the audio player with initWithData:error: solves this.
For example:
NSData* data = [NSData dataWithContentsOfURL:url] ;
AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:outError];
Disappointing that apple initializes their audio player based on extension, instead of looking at the binary data and trying to figure out which type of data they received.
Found the solution!
Turns out that if I simply use AVPlayer instead of AVAudioPlayer and if I use .acc as the extension of the file, then it plays just fine. now I can play both aac and mp3 files.
.aac file can be played,try to check whether the file exists?
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: backgroundMusicPath ] == YES)
{
NSLog(#"find file");
}

AVAudioPlayer sound file location not changing / updating

*This is my first stackoverflow question so apologies if I am doing something wrong.
I am trying to create a simple sound board app. I'm having trouble getting my AVAudioPlayer on xCode 4.1 (iOS 6.1.2) to update where the sound file to play is located. I wanted to avoid having multiple audio players (audioPlayer2, audioPlayer3, etc) so I am trying to use the same audio player but instead, update where the sound file is located. I only want one sound playing at a time so multiple sounds is obviously not an issue. Here is my code:
- (IBAction)play {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
//I added the next two lines to allow me to play AVAudio with MPiPodPlayer (which I found on this site, too) simultaneously.
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start setTitle:#"Start" forState:UIControlStateNormal];
}
}
- (IBAction)play2 {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/chicken.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start2 setTitle:#"Stop" forState:UIControlStateNormal];
clicked = 1;
clicked2 = 0;
} else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start2 setTitle:#"Start" forState:UIControlStateNormal];
clicked = 0;
}
}
My IBActions are linked to UIButtons and the 'start's are UIButton references. Whenever I click on 'start' it plays 'k.mp3' fine, however if I then click on 'start2' AFTER it starts to play the 'k.mp3' file, and not the chicken file. Whichever button I click on first is what the url is set to. This is my first iPhone OS application project so I realize there are probably some embarrassing coding mistakes in there (feel free to correct me). I'd like an answer that would be applicable to multiple buttons, even for some 30 buttons so I do not have to copy and paste stop audio player 1, 2, and 3 for each button.
To summarize: I have multiple buttons that play one sound each, I would like no more than one sound playing at a time; when I click on a button it plays 1 sound and all other audio players stop. I would prefer having only one AVAudioPlayer instance for simplicity. Thanks in advance!
Check if application control goes into - (IBAction)play2
And if control goes in it and it is still not working then you might try [audioPlayer release] before
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
that might do the trick for you

Resources