My app currently plays an mp3 audio file while the user is searching for another active user on the app.
In my app delegate, I ask for more background time to continue performing the search:
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background handler called. Not running background tasks anymore.");
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}];
}
When the user sends the app to the background, the audio continues to play as the search algorithms continue to work.
However, I would like for there to be the red indicator bar across the top of the screen, similar to what you would see when a VOIP call is performing on an app in the background.
Is this possible?
Here is my audio player code in SearchView.m
NSString *path = [NSString stringWithFormat:#"%#/searchTune.mp3", [[NSBundle mainBundle] resourcePath]];
NSURL *soundUrl = [NSURL fileURLWithPath:path];
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
[_audioPlayer play];
No, its not possible. No public API for that, iOS uses private API's for their internal use. It is called pulsating status bar.
Related
We developed this iOS scenario:
1) iOS App schedules local push notification
2) Push is a trigger to start AVAudioPlayer audio playing - even if the iPhone is locked (app in background)
Now there are two scenarios:
a) Time difference between push scheduling is more than 3 hours:
Audio does start playing after unlocking and starting the app
b) Time difference between push scheduling is less than 3 hours:
Audio does start playing even without unlocking
We want case b as default case. Does iOS stop/freeze our application after some hours? Interesting: On indian devices there does not seem to be case a - even if time difference is more than 12 hours.
Any ideas?
Thanks so much!
Did you integrate background execution? Otherwise the app will be suspended after a while.
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Once didReceiveLocalNotification method triggered in appdelegate, then trigger one method in appdelegate or in global then use below code to play audio file using AVAudioPlayer in background or device lock
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#“filename”
ofType:#“type”];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL
error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
player.numberOfLoops = -1; //Infinite
[player prepareToPlay];
[player play];
I have an app mostly based around Core Bluetooth.
When something specific happens, the app is woken up using Core Bluetooth background modes and it fires off an alarm, however I can't get the alarm working when the app is not in the foreground.
I have an Alarm Singleton class which initialises AVAudioPlayer like this:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:soundName
ofType:#"caf"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[self.player prepareToPlay];
self.player.numberOfLoops = -1;
[self.player setVolume:1.0];
NSLog(#"%#", self.player);
This is the method that is called when my alarm code is called:
-(void)startAlert
{
NSLog(#"%s", __FUNCTION__);
playing = YES;
[self.player play];
NSLog(#"%i", self.player.playing);
if (vibrate) {
[self vibratePattern];
}
}
Now when the app is in the foreground, self.player.playing returns 1 however when the app is in the background self.player.playing returns 0. Why would this be?
All the code is being called, so the app is awake and functioning.
The vibrate works perfectly which uses AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Any idea why this sound won't play?
Thanks
Apple has a nice Technical Q&A article about this in its documentation (see also Playing and Recording Background Audio).
I think one big thing missing is that you haven't activated the Audio Background Mode in the Xcode settings:
Maybe also adding [self.player prepareToPlay] in your alert method is helpful.
I have an App than also needs background audio but my App works with the App background mode "Voice over IP" as it needs to record sometimes. I play background audio telling the App singleton I need to play audio in background:
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
if([thePlayer play]){
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
EDIT: You must call [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL]; before your app goes to background. In my app, it is at the same time you start playing, in yours, if the player might be started in background, you should do:
- (void)applicationDidEnterBackground:(UIApplication *)application{
// You should retain newTaskId to check for background tasks and finish them
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
Apple docs
Either enable audio support from the Background modes section of the Capabilities tab
Or enable this support by including the UIBackgroundModes key with the audio value in your app’s Info.plist file
I take it you have the audio background mode specified for the app. Even so, I'm not sure you can set an audio session to be active while in the background. You need to have activated it before going into the background. You may also need to play some silent audio to keep this active, but this is seems like bad practice (it may drain the battery). Looking at the docs for notifications there seems to be a way to have a local notification play an audio sample that's included in your bundle, which seems to be what you want to do, so maybe that's the way to go.
Try this :
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
link
Try this http://www.sagorin.org/ios-playing-audio-in-background-audio/
You need to enable your app to handle audiosession interruptions (and ended interruptions) while in the background. Apps handle audio interruptions through notification center:
First, register your app with the notification center:
- (void) registerForMediaPlayerNotifications {
[notificationCenter addObserver : self
selector: #selector (handle_iPodLibraryChanged:)
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];
}
Now save player state when interruption begins:
- (void) audioPlayerBeginInterruption: player {
NSLog (#"Interrupted. The system has paused audio playback.");
if (playing) {
playing = NO;
interruptedOnPlayback = YES;
}
}
And reactivate audio session and resume playback when interruption ends:
-(void) audioPlayerEndInterruption: player {
NSLog (#"Interruption ended. Resuming audio playback.");
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (interruptedOnPlayback) {
[appSoundPlayer prepareToPlay];
[appSoundPlayer play];
playing = YES;
interruptedOnPlayback = NO;
}
}
Here's Apple's sample code with full implementation of what you're trying to achieve:
https://developer.apple.com/library/ios/samplecode/AddMusic/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008845
I was also facing the same problem, but i was only facing it only during initial time when i was trying to play a sound while app was in background, once the app comes in foreground and i play the sound once than it works in background also.
So as soon as app is launched/ login is successful in my case, i was running this code:
[self startRingcall];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self stopRingcall];
});
- (void)startRingcall
{
if( self.audioPlayer )
[self.audioPlayer stop];
NSURL* musicFile = [NSURL fileURLWithPath:[[[UILayer sharedInstance] getResourceBundle] pathForResource:#"meetcalling" ofType:#"caf"]];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&error];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (error != nil) {
NSLog(#"meetringer sound error -> %#",error.localizedDescription);
}
self.audioPlayer.volume = 0;
[self.audioPlayer play];
self.audioPlayer.numberOfLoops = 1;
}
- (void)stopRingcall
{
if( self.audioPlayer )
[self.audioPlayer stop];
self.audioPlayer = nil;
}
I'm building a running app that notifies the user by audio that they need to start running or start walking every couple of minutes. I was able to get the sound to run in the background, even with the lock screen on using AVAudioPlayer.
Here's snippets of what I have:
ViewController.h
#property (nonatomic, strong) AVAudioPlayer *audioWalk;
ViewController.m
- (void)viewDidLoad{
[super viewDidLoad];
// Walk Audio File
NSString *soundFile2 = [[NSBundle mainBundle] pathForResource:#"Walk" ofType:#"wav"];
audioWalk = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundFile2] error:nil];
// Load the audio into memory
[audioWalk prepareToPlay];
// Permit the timer to run in the background
bgTask = 0;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
// Prevent the application from going to sleep while it is running
[UIApplication sharedApplication].idleTimerDisabled = YES;
// Starts recieving remote control events and is the first responder
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
// Plays audio
[audioWarmup play];
}
I'm trying to figure out how to play my audio without interrupting the music that is playing in the background. Also, the sounds need to play in the background and when the screen is locked. Any help would be much appreciated!
I was able to fix it. Here's what I did below. This solutions allows an audio file to run in the background, even with the lock screen, while not interrupting or pausing audio from other applications (particularly music).
- (void)viewDidLoad{
[super viewDidLoad];
// Play audio even if lock screen is on, the with options allows audio from other applications to play without interruption
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error: nil];
[[AVAudioSession sharedInstance] setActive: YES error:nil];
// Walk Audio File
NSString *soundFile2 = [[NSBundle mainBundle] pathForResource:#"Walk" ofType:#"wav"];
audioWalk = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundFile2] error:nil];
// Load the audio into memory
[audioWalk prepareToPlay];
// Permit the timer to run in the background
bgTask = 0;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
// Prevent the application from going to sleep while it is running
[UIApplication sharedApplication].idleTimerDisabled = YES;
// Starts receiving remote control events and is the first responder
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
// Plays audio
[audioWarmup play];
}
I am using AVAudioPlayer and NSFileHandle to do audio streaming. The basic idea is that I save the streaming audio data to the device with file system and then use AVAudioPlayer to playback the file just saved. AVAudioPlayer can still play that file even the streaming is in progress.
I have a UIButton to start streaming/downloading. When the downloaded data is accumulated to a specific amount of Bytes, AVAudioPlayer will play (the "play" method of AVAudioPlayer is triggered) automatically. My question is: I tap the button to start streaming/downloading, then press iPhone's home button very soon to make my app go to background. The download keeps working in the background but the "play" method of AVAudioPlayer returns "NO" which means the "play" method doesn't play the audio.
I added AVAudioSession related code to my audio player's init method:
- (id) initWithURL:(NSString *) downloadedMusicURL
{
if ((self = [super init]))
{
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
CFURLRef url = CFURLCreateWithFileSystemPath (NULL, (CFStringRef)downloadedMusicURL, kCFURLPOSIXPathStyle, FALSE);
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:CFBridgingRelease(url) error:nil];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
}
return self;
}
Also in the info.plist I added an item "App plays audio" for the Key "Required background modes". However, the "play" still doesn't get called properly in the background. What else did I miss? Thanks a lot in advance.
Your app cannot start playing audio in the background. And this makes sense. Think what the device would be like if an app that the user is not actively using could suddenly start producing sound! Remember, to the user, sending an app to the background is the naive equivalent of quitting that app. Your app must not rise like a zombie from the dead and start making noise!
The background audio setting allows your app that was producing audio while in the foreground to continue to do so when it then goes into the the background. It then can continue being in charge of the audio (if it receives remote events) until some other app produces sound; after that, your app is once again out of the running until it is brought to the foreground and produces sound.
So you'll need to start playing some sound before your app goes into the background, if you want this to work.
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
/*
And
in info.Plist file
Required background modes : App PLAYS Audio
*/
Please use this code in - (void)applicationDidEnterBackground:(UIApplication *)application
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
AudioSessionSetActive(false);
and use this code in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
AudioSessionInitialize (NULL,NULL,NULL,NULL);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory,sizeof (sessionCategory),&sessionCategory);
AudioSessionSetActive(true);
hope this helps.
Faced this very problem. Let me suggest you to use AVAudioSessionCategoryOptionMixWithOthers with -setCategory:withOptions:error:. Also, probably it makes sense to activate the session after you set the category, not before.
I have an app which plays and controls music across different ViewControllers. To do this, I created two instances of AVAudioPLayer in the app delegate's DidFinishLaunchingMethod:
NSString *path = [[NSBundle mainBundle] pathForResource:#"minnie1" ofType:#"mp3"];
NSURL *path1 = [[NSURL alloc] initFileURLWithPath:path];
menuLoop =[[AVAudioPlayer alloc] initWithContentsOfURL:path1 error:NULL];
[menuLoop setDelegate:self];
menuLoop.numberOfLoops = -1;
[menuLoop play];
NSString *path2 = [[NSBundle mainBundle] pathForResource:#"minnie2" ofType:#"mp3"];
NSURL *path3 = [[NSURL alloc] initFileURLWithPath:path2];
gameLoop=[[AVAudioPlayer alloc] initWithContentsOfURL:path3 error:NULL];
gameLoop.numberOfLoops = -1;
[gameLoop setDelegate:self];
[gameLoop prepareToPlay];
After this I call it in various viewControllers, to stop or restart using code like:
- (IBAction)playGameLoop{
NSLog(#"Begin playGameLoop");
FPAppDelegate *app = (FPAppDelegate *)[[UIApplication sharedApplication] delegate];
if ([FPAVManager audioEnabled] == NO){
//DO NOTHING
}
else {
if (app.gameLoop.playing ==YES ) {
//DO NOTHING
}
else { [app.gameLoop play];
NSLog(#"End playGameLoop");
}
}
The audio files play fine the first time and they stop when asked to stop. Though, on iOS4 devices, they won't start replaying when called again.
Thanks!
From the docs:
Calling this method [stop] or allowing a sound to finish playing,
undoes the setup performed upon calling the play or prepareToPlay
methods.
The stop method does not reset the value of the currentTime property
to 0. In other words, if you call stop during playback and then call
play, playback resumes at the point where it left off.
Where you are looping the sounds, I would expect to be able to call stop and then call play. But I have fuzzy recollection of running into this myself. I found that calling pause, rather than stop, was a better solution. Especially since I could then call play again to resume play. Calling stop always seemed to require calling prepareToPlay again before calling play, at least in my experience.
It's possible that there were some changes in the API implemetation between iOS4.x and iOS5, too. You should check the API diffs on the Developer web site to be sure.