AVAudioPlayer cannot play music with a NSTimer in background - iphone

I want to play music with an AVAudioPlayer using an NSTimer, but [player prepareToPlay] returns NO & doesn't play in the background.
Can somebody give me some idea?
Here's my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(playMusic:) userInfo:nil repeats:NO];
[self.window makeKeyAndVisible];
return YES;
}
- (void)playMusic:(NSTimer *)timer{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
NSString *fileName = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"Apologize.mp3"];
NSURL *fileUrl = [NSURL fileURLWithPath:fileName];
NSError *error;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error];
if ([player prepareToPlay]) {
[player play];
NSLog(#"start!");
}else{
NSLog(#"error msg :%#",error);
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
if ([[UIApplication sharedApplication] respondsToSelector:#selector(beginReceivingRemoteControlEvents)]){
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
UIBackgroundTaskIdentifier backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
// /* just fail if this happens. */
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
}];
}

You need to do this init in the viewDidLoad :
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"test"
ofType:#"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
This is for the audio initialization. Here, with a MP3 named test, imported in the project.
Note that the beginReceivingRemoteControlEvents part is very important. Without it, you cannot start playing from background, just keep on listening to music already playing from foreground.
Now you need to listen to the event didEnterInBackGround (you could go with the applicationDidEnterBackground of your app delegate, but this way you can put the code in the class it belongs to):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didEnterBG:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
And now in that didEnterBG method :
self.backgroundTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(backgroundWork) userInfo:nil repeats:YES];
[self.backgroundTimer fire];
Here i make this sound repeat every 10s for personal reasons, but do whatever you need.
Finally, the backgroundWork method :
- (void)backgroundWork{
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
}
Now your audio file is playing in background :-)
You should also note that your app need to have specific rights to keep doing jobs in background. You need to check the box under 'YourTarget' -> Capabilities -> Background Modes : Audio and AirPlay. Otherwise, the OS will terminate you app in a few minutes in real conditions (with no debugger or instrument).

before going to code. you need to tell the OS that you want permission to play music in background.
you can do that by setting a Key in your app's info.plist
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
doing so, you will be able to play audio when app moves to background.

I have the same issue, but I found the solution from this post: http://developer.apple.com/library/ios/#qa/qa1668/_index.html
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError) { /* handle the error condition */ }
NSError *activationError = nil;
[audioSession setActive:YES error:&activationError];
if (activationError) { /* handle the error condition */ }

Related

AVPlayer background issue

I have a problem with AVPlayer, when I tried to make the player working on the background, the iPhone 6.0 simulator works fine, but the sound on the real device disappears when the application goes to the background!
- (IBAction)RayaFM {
NSURL *URLA = [NSURL URLWithString:#"http://live.raya.fm:8032/;stream.mp3"];
self.player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithURL:URLA]];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
[self.player play];
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
if (newTaskId != bgTaskId != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
bgTaskId = newTaskId;
}
You also need to include the following in your -info.plist file:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
See http://developer.apple.com/library/ios/#qa/qa1668/_index.html

iPhone App : Starting to play music very slow

Am working on an iPad/iPhone App & am playing a background music with this code snippet which I call in the Delegate's didFinishLaunchingWithOptions method:
-(void) playMusic {
NSLog(#"play music!");
NSString *sound_file;
if ((sound_file = [[NSBundle mainBundle] pathForResource:#"musicfile" ofType:#"mp3"])){
NSURL *url = [[NSURL alloc] initFileURLWithPath:sound_file];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
self.audioPlayer.delegate = self;
[self.audioPlayer setNumberOfLoops:-1]; // Infinite loop
[self.audioPlayer prepareToPlay];
[self.audioPlayer setVolume:0.2];
[self.audioPlayer play];
} else {
NSLog(#"WARN : music file not found!");
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
}
But I see that this method alone is taking 0.43 seconds on an average, which is a lot! Am I doing it the right way? Or is there a faster way to start the music play ? Please help.
My environment : iOS5, XCode 4.3, iPad 2.0 is what I tested this with now

How to play an audio when home button clicked in iphone sdk

Now am developing an application in which the application will play the audio automatically when the home button is tapped (when entering the background mode), below is my code i've used. it works perfectly in simulator but not working in any of the devices (iPhone, iPad, iPod). please guide me to go further...
- (void)applicationDidEnterBackground:(UIApplication *)application {
AVAudioSession * session = [AVAudioSession sharedInstance];
[session setDelegate: self];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
NSURL * url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#.wav", [[NSBundle mainBundle] resourcePath], soundName]];
AVAudioPlayer * audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
audioPlayer.numberOfLoops = -1;
[audioPlayer setVolume:1.0];
[audioPlayer prepareToPlay];
[audioPlayer play];
}
- (void)applicationWillResignActive:(UIApplication *)application {
NSAssert(backgroundTask == UIBackgroundTaskInvalid, nil);
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}
I don't think you can do this, when the app is going into the background audio is muted thus the sound you play will nog be heard.
And this will be very annoying and should just not be done, also the simulator reacts differently than then a real iOS device.
An app can only play audio that has been started before entering background mode. Note that an app can play silent audio, but Apple has rejected apps that play a lot of silence.

playing audio while in background mode doesnt work

In my application audio is not being played when i put my application in background mode ..i have seen such issues in this site itself.it is mentioned that
1) in the app-info.plist add to background modes "audio"
2) in the code i added support for audio sessions
if([player isPlaying])
{
[player stop];
}
NSError *error=nil;
int trackid=arc4random()%10+1;
NSString *trackname=[NSString stringWithFormat:#"trk-%d",trackid];
NSLog(#"%#",trackname);
NSString *newAudioFile = [[NSBundle mainBundle] pathForResource:trackname ofType:#"mp3"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:newAudioFile] error:NULL];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (setCategoryError) { /* handle the error condition */ }
NSError *activationError = nil;
[audioSession setActive:YES error:&activationError];
if (activationError) { /* handle the error condition */ }
if(error) {
NSLog(#"%#",&error);
}
[player prepareToPlay];
[player play];
player.numberOfLoops=1;
but still it is not working when i put the application in backgroud mode.it resumes when i put the application back.have i missed something?
use this line in the - (void)viewDidLoad
[UIApplication sharedApplication].idleTimerDisabled = YES;

restarting a (audio) loop after it has finished

I want to play an audio loop by turning on a switch but i do not want the loop to end until the switch is turned off. When the loop ends i want it to simply start back at the beginning as to be continuos.
Try something like this. Note the -1 tells the music to repeat indefinitely:
Import this file at the top of your file:
#import <AVFoundation/AVFoundation.h>
Then to use it:
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:resourcePath ofType:#"caf"];
NSError *activationError = nil;
NSError *audioPlayerInitError = nil;
[[AVAudioSession sharedInstance] setActive: YES error:&activationError];
NSURL *newURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:newURL error:&audioPlayerInitError];
[newPlayer prepareToPlay];
[newPlayer setVolume:.8];
[newPlayer setNumberOfLoops:-1]; // -1 means play indefintely
[newPlayer setDelegate: self];
[newPlayer play];
[newPlayer release];
And then to stop it you would do:
if ([newPlayer isPlaying]) {
[newPlayer stop];
}