Handle audio interruptions AVAudioPlayer - iphone

I am playing "sound effects" in my app when buttons are clicked and such and I have been having some difficulties getting the delegates to work properly within the AVAudioPlayer class to keep the music playing after the sound. I have the framework imported and delegates set but I can not seem to get the AVAudioSession shared instance to work... I know I am missing something but can not seem to find a clear answer anywhere even within apples docs. Here is the code I am using trying to accomplish this.
#import "AVFoundation/AVAudioPlayer.h
#import "MediaPlayer/MediaPlayer.h"
#interface HomeViewController : UIViewController <AVAudioPlayerDelegate, MPMediaPlayback
> {
When a button is pushed
-(IBAction)About
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button" ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
AboutViewController *about = [[AboutViewController alloc] init];
[self presentModalViewController:about animated:YES];
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"move" ofType:#"caf"];
AVAudioPlayer* theAudio1 = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path1] error:NULL];
theAudio.delegate = self;
[theAudio1 play];
}
Delegates trying to either play my sound as a "ambient noise" or just resume play after my sound happens
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
}
-(void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
}
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags
{
if (flags)
{
AVAudioPlayer *audio = [[AVAudioPlayer alloc] init];
[audio setDelegate:self];
[audio play];
}
}
Now the last delegate from what I understand is the only delegate of use really in my case and what I have will not work since I need to be using the [AVAudioSession SharedInstance] like this but I can not seem to get the AVAudioSession to work!
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags
{
if (flags == AVAudioSessionFlags_ResumePlay)
{
[player play];
}
}
Any help or suggestions would be greatly appreciated. I basically just need to know how to get the [AVAudio SharedInstance] so if anyone knows what class I need to import or framework I need to add to get this working it would be very much obliged!
Thanks

Related

XCODE IOS memory leak for AVAudioPlayer

I use ARC.
Here is the method for starting the audio in my code:
.h file:
#property (retain,nonatomic)AVAudioPlayer *myAudio;
and .m files
-(void)myPlaySound:(NSString *)mySoundFile NumberOfLoops:(int)loopsCount ofType:(NSString *)fileType
{
if([myAudio isPlaying])
{
[myAudio stop];
}
NSURL* musicFile = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:mySoundFile
ofType:fileType]];
NSError *error;
myAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&error];
self.theAudio = myAudio;
myAudio.volume = audioVolume;
myAudio.numberOfLoops = loopsCount;
myAudio.currentTime = 0.0;
[myAudio prepareToPlay];
if([myAudio play] == NO)
{
NSLog(#"error");
}
}
Based on the button press, I play different audio files of different length and bit rate and types.
Its working, but I get memory leak issue.

How to auto play music as soon as my app starts?

I need some help with my app I have recently started. I am a very big starter to coding so please do help me, it'll mean a lot. I need a piece of music to play as soon as the user enters my app, i have followed other youtube tutorials but they only work for the older Xcode versions, so please help thank you so much.
How about putting it in you application didFinishLaunching but be sure to instantiate it in you .h and .m.
Something like this should do your problem:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
resourcePath = [resourcePath stringByAppendingString:#"/YOURMUSICNAME.wav"];
NSLog(#"Path to play: %#", resourcePath);
NSError* err;
//Initialize our player pointing to the path to our resource
player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath] error:&err];
if( err ){
//bail!
NSLog(#"Failed with reason: %#", [err localizedDescription]);
}
else{
//set our delegate and begin playback
player.delegate = self;
[player play];
player.numberOfLoops = -1;
player.currentTime = 0;
player.volume = 1.0;
}
}
Then if you want to stop it:
[player stop];
or pause it :
[player pause];
and also import it in your header file:
#import <AVFoundation/AVFoundation.h>
EDIT:
You should to ofcourse declare it in your header, then synthesize it.
//.h and add the bold part:
#interface ViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
}
#property (nonatomic, retain) AVAudioPlayer *player;
//.m
#synthesize player;
You can use the AVAudioPlayer. It pretty straight forward to use:
NSURL *path = [[NSURL alloc] initFileURLWithPath:[DataPersister getQualifiedPathForFileInDirectory:DataPersisterPathBundle fileName:#"music.mp3"]];
NSError *outError;
AVAudioPlayer *musicSound = [[AVAudioPlayer alloc] initWithContentsOfURL:path error:&outError];
[musicSound play];
[path release];
Remember to import
#import <AVFoundation/AVFoundation.h>
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/MUSIC.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = -1;
[audioPlayer play];
audioPlayer.volume = 1.0;
audioPlayer.currentTime = 2;
Use this at - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method will play music for sure
Happy Coding ;)

AVAudioPlayer only calls audioPlayerDidFinishPlaying twice

I'm trying to create a sort of audio playlist using AVAudioPlayer. So I've used the following code:
.h
<AVAudioPlayerDelegate>
{
AVAudioPlayer *audioPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *audioPlayer;
.m
#synthesize audioPlayer;
- (void)viewDidLoad
{
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
audioPlayer.numberOfLoops = 0;
audioPlayer.delegate = self;
[audioPlayer play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag)
{
[player release];
currentSong = currentSong + 1;
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[songs objectAtIndex:currentSong] ofType:#"mp3"]];
artist.text = [artists objectAtIndex:currentSong];
song.text = [songs objectAtIndex:currentSong];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
audioPlayer.delegate = self;
audioPlayer.numberOfLoops = 0;
[audioPlayer initWithContentsOfURL:url error:nil];
[audioPlayer play];
}
}
This works for two songs, but after this there isn't any audio. Any idea why this is?
Thanks,
Denis
In this line you are initing an audio player:
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
Then you are initing it again in this line (unneeded duplication, and probably an additional retain):
[audioPlayer initWithContentsOfURL:url error:nil];
Then the next time the loop comes around, even though you release it using the line
[player release];
…there is a problem as it is still in memory, tying up a hardware codec or wasting resources. Try removing the second initWithContents… line as it is unnecessary.
1.Just maintain an array.
2.Once you create an instance of audioPlayer - add to the array and call play and release the instance of audioPlayer(since it will get retained once you added to array).
3.In audioPlayerDidFinishPlaying remove the audioPlayer from that array.
So you can play multiple files at a time

iOS - How to stop background music when changing views

How to stop background music when changing views? I have no clue. If i press a button which takes me to a new view, there is new background music. But the old background music (which goes in an infinite loop) keeps on going. Please help! also sample some code please, here is mine:
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"MathMusic2" ofType:#"wav"];
AVAudioPlayer* theAudio= [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
theAudio.numberOfLoops = -1;
[super viewDidLoad];
}
I just need to know how to make the background music from the new view stop playing. And vice versa when i press the back button from the new view
Create a property for the AVAudioPlayer *theAudio so you can access the audioPlayer from any point in your class.
Header file of viewController
...
AVAudioPlayer *theAudio;
...
#property (nonatomic, retain) AVAudioPlayer *theAudio;
Implentation file of viewController
...
#synthesize theAudio;
...
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"MathMusic2" ofType:#"wav"];
self.theAudio= [[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL]] autorelease];
theAudio.delegate = self;
[theAudio play];
theAudio.numberOfLoops = -1;
[super viewDidLoad];
}
If viewWillDisappear is called you can then just stop the audio with
- (void)viewWillDisappear
{
[theAudio stop];
}
it gaves errors in here :
"theAudio.delegate = self;" as something like assigning to id...
its yellow anyway..
still when i change view and go to another class music not stoping....

Playing multiple sounds at once?

I have 6 sounds on one view.
However I want it so that I can play more than one at once, So you tap sound 1 (sound 1 is playing) then sound 2 plays. while sound 1 is still playing.
But at the moment I press sound 1 (sound 1 plays), press sound 2 (sound 2 plays, but sound 1 stops)
Here is the code for the audio part.
- (IBAction)oneSound:(id)sender; {
NSString *path = [[NSBundle mainBundle] pathForResource:#"1" ofType:#"wav"];
if (theAudio) [theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(updateVolume) userInfo:nil repeats:YES];
}
- (IBAction)twoSound:(id)sender; {
NSString *path = [[NSBundle mainBundle] pathForResource:#"2" ofType:#"wav"];
if (theAudio) [theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(updateVolume) userInfo:nil repeats:YES];
}
There is some important code missing, but it looks as if theAudio is a global you are using to manage the playing of your sounds. Since you destroy it whenever a sound is played whatever is currently playing will stop in preparation for the next sound.
There are several ways to fix this, one being that each sound gets its own unique AVAudioPlayer instance.
don't release the player just because it exists. release when finished playing
You should implement this in the app delegate or a property of the app delegate so that the delegate reference remains valid if you pop the view.
You should not need to do this for each voice. Each voice will initial the player with a different filename or URL. You gain this by making sure that you will release when finished playing. The other thing to take care of is releasing players if the player doesn't finish because of an interruption.
#pragma mark -
#pragma mark Audio methods
-(void)playNote:(NSInteger)noteNumber {
NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i", noteNumber ]
ofType: #"caf"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
AVAudioPlayer *playerToPrepare = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
error:nil];
[fileURL release];
[playerToPrepare prepareToPlay];
[playerToPrepare setDelegate: self];
[playerToPrepare play];
}
#pragma mark -
#pragma mark AVAudioPlayer delegate methods
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) playerThatFinished
successfully: (BOOL) completed {
if (completed) {
[playerThatFinished release];
}
}
You can declare and use:
AVAudioPlayer *theAudio1; // for file 1.wav
AVAudioPlayer *theAudio2; // for file 2.wav
...
AVAudioPlayer *theAudio6; // etc.
instead of releasing and reusing just one AVAudioPlayer.