Stop Audio on ViewDidDissapear - ios

I finally have my audio playing in a loop with ViewDidLoad but I'm really struggling to get it to stop with ViewDidDissapear. I've read this and this plus many answers and questions on this forum. If I use [theAudio stop] I get an error and most of the other tutorials end up with errors. What am I doing wrong?
I have imported the AVFoundation/AVFoundation.h Framework and added AVAudioPlayerDelegate
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"safariSFX" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio play];
theAudio.numberOfLoops = -1;
[super viewDidLoad];
}

You need to store the AVAudioPlayer instance as a #property. That way when theViewWillDisappear event occurs, you can call [theAudio stop]; In your code above you create a local var and so don't have any way to reference it later on.

your code is out of scope.
You need to make theAudio an ivar if you want to be able to call it from viewWIllDisappear.
// In viewDidLoad -- you will need to setup theAudio in viewWillAppear if you are going to come back to this viewcontroller
if(theAudio == nil){
//initialize theAudio if it is nil
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
}
//begin playing
[theAudio play];
.
.
.
-(void)viewWillDisappear{
//cleaning up if theAudio isn't nil, stop playing and set to nil;
if(theAudio != nil){
[theAudio stop];
theAudio = nil;
}
}

Related

Proper use of AVAudioPlayer

The application I'm building is essentially an instrument with ten buttons, each linked to a separate AVAudioPlayer. When I try and allocate and initialize memory for each AVAudioPlayer in the ViewDidLoad method, I get no errors however the responsiveness of each button lags and there is considerable lag time before the same button can be triggered/heard again. I've rectified this situation by implementing the code below, however I'm not convinced it's the proper way of handling memory, especially because I have 10 of these methods.
- (IBAction)note1:(id)sender {
url1 = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"note1" ofType:#"wav"]];
unit1 = [[AVAudioPlayer alloc] initWithContentsOfURL:url1 error:nil];
[unit1 play];
}
One thing you can try,
Call prepareToPlay method of AVAudioPlayer before playing that file.
The problem with your current code is that you are creating new instance of AVAudioPlayer every time you call a -note1: You can try this improvement:
- (IBAction)note1:(id)sender {
if (!url1)
url1 = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"note1" ofType:#"wav"]];
if (!unit1)
unit1 = [[AVAudioPlayer alloc] initWithContentsOfURL:url1 error:nil];
[unit1 play];
}
However best way is to initialise your AVAudioPlayers at one place, when your UIViewController is loaded:
- (void) initializePlayers {
url1 = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"note1" ofType:#"wav"]];
unit1 = [[AVAudioPlayer alloc] initWithContentsOfURL:url1 error:nil];
}
- (void) viewDidLoad {
[self initializePlayers];
}
- (IBAction)note1:(id)sender {
[unit1 play];
}
Do any additional setup after loading the view, typically from a nib.
NSURL* url = [[NSBundle mainBundle] URLForResource:#"Rondo_Alla_Turka_Short" withExtension:#"aiff"];
NSAssert(url, #"URL is valid.");
NSError* error = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}

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.

Cannot play audio in Xcode project

This code works in a test app, but not in the app in which I want the audio to play.
-(void) playTutorialAudio
{
_theAudioFile = [[NSBundle mainBundle] pathForResource:#"Welcome" ofType:#"mp3"];
NSLog(#"playTutorialAudio _theAudioFile %#",_theAudioFile);
NSURL *playTutorialURL = [NSURL fileURLWithPath:_theAudioFile ];
_audioPlayAlert = [[AVAudioPlayer alloc] initWithContentsOfURL:playTutorialURL error:NULL];
[_audioPlayAlert setDelegate:self];
[_audioPlayAlert prepareToPlay];
_audioPlayAlert.volume = 1.0;
[_audioPlayAlert play];
}
The code works with other audio files.
It will work, You need to change your implementation like this. Please notice your init method.
#property (nonatomic, retain) AVAudioPlayer *cellTapSound;
may be in viewDidLoad
cellTapSound = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"ting" withExtension:#"wav"] error:nil];
[cellTapSound prepareToPlay];
Now may be on click of some button, you can give a shot like this :
if (cellTapSound.isPlaying) [cellTapSound setCurrentTime:0.0];
[cellTapSound play];
hope that helps.

iOS background music problems [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iOS SDK : playing music on the background and switching views
Hi guys im currently using this code to play background music in my app when its launched .But when i switch views to my SecondView and return back to my Firstview the music starts over and overlaps the music that is currently playing and it keeps overlapping music when i return back to my Firstview, how can i have the music start over when i switch back to my Firstview from my SecondView.
FirstViewController.m
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"drums" ofType:#"mp3"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPathath] error:NULL];
theAudio.delegate = self;
theAudio.numberOfLoops = -1;
[theAudio play];
You can use NSUserDefaults to save the music playing status, so when the view is loaded, the music will only be played if it hasn't already.
if ([[NSUserDefaults standardUserDefaults] stringForKey:#"music"] == nil) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"drums" ofType:#"mp3"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPathath] error:NULL];
theAudio.delegate = self;
theAudio.numberOfLoops = -1;
[theAudio play];
[[NSUserDefaults standardUserDefaults] setObject:#"-" forKey:#"music"]; }
You need to reset this key back to nil when quitting the app. Otherwise, if the player quit the app, and next time when the app is restarted the #"music" string wouldn't be nil.
Go to the projectAppDelegate.m file:
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"music"]; }
If the music is being played throughout the app, then put the music playing codes as shown below to be safe. Don't forget to declare the AVAudioPlayer *theAudio in projectAppDelegate.h file.
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSString *path = [[NSBundle mainBundle] pathForResource:#"drums" ofType:#"mp3"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPathath] error:NULL];
theAudio.delegate = self;
theAudio.numberOfLoops = -1;
[theAudio play];
[[NSUserDefaults standardUserDefaults] setObject:#"-" forKey:#"music"]; }
I might have missed a few bits here. Just run a few tests to make it the way you like to work. I just tried on my app and it worked for me.
Two option,
1- stop the player while first view is disappear.
[theAudio stop] in `viewWillDisappear`
2- if you don't want to play again on come back.
declare theAudio in appDelegate class. and before allocating check whether it is allocated or not.
if(!appDelegate.theAudio)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"drums" ofType:#"mp3"];
appDelegate.theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPathath] error:NULL];
theAudio.delegate = self;
theAudio.numberOfLoops = -1;
[theAudio play];
}
else
{
[theAudiostop];
[theAudio play];
}
You are reallocating and recreating the AVAudioPlayer each time you display the view. You should avoid this if possible. As a solution to your problem, depending on your code, call [theAudio stop] in viewDidDisappear or viewDidUnload events. This will stop your audio player when its view enters background.

Pick songs from plist(NSArray) and play using AVAudioPlayer?

I'm student working on a coding exercise and I am stumped!
I have two instances of AVAudioPlayer in my app - I can load the songs into each player using a direct path no problem.
What I'd like to be able to do is play multiple songs held within an array on each player.
Is this possible? and if so how would I go about doing this?
In my plist I have the key set to "One.mp3" as a string and the value as the path to the file... (was guessing at that part).
Thanks for any insight.
- (void)viewDidLoad {
[super viewDidLoad];
//multiple song array
NSString *soundsPath = [[NSBundle mainBundle] pathForResource:#"soundslist"
ofType:#"plist"];
soundsList = [[NSArray alloc] initWithContentsOfFile:soundsPath];
NSString* filename = [soundsList objectAtIndex:0];
NSString *path = [[NSBundle mainBundle] pathForResource:filename
ofType:#"mp3"];
AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path]
error:NULL];
self.audioPlayer = newAudio; // automatically retain audio and dealloc old file if new file is loaded
[newAudio release]; // release the audio safely
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer setNumberOfLoops:0];
[audioPlayer play];
}
It sounds like you want to try to play multiple songs on a single player. This isn't possible as stated in the AVAudioPlayer Overview (4th bullet). It is possible to play multiple songs with multiple AVAudioPlayers. Something like this:
NSMutableArray *audioPlayers = [NSMutableArray arrayWithCapacity:[soundsList count]];
for (NSString *soundPath in soundsList) {
NSError *error = nil;
AVAudioPlayer *audioPlayer = [AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[audioPlayers addObject:audioPlayer];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer setNumberOfLoops:0];
[audioPlayer play];
}
I would suggest that you hardcode the file path instead of reading it in with a plist. Once you get that working, then you can try reading it in with the plist. Something like this would work:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"One" withExtension:#"mp3"];
AVAudioPlayer *soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error]
This way, you remove one level of indirection and one point of failure.

Resources