Recently,I try to make an app needs working in background and I use audio to protect the app from being killed by ios.Neither voip nor bluetooth,and not a Luckily,the demo works well until a new app execute which also run in background and also run by something audio.Then the demo was killed after 10 mins later,can anyone help me with the trouble?There must be other Thanks!!later i found an new app which do well in background mode.And here is the url :https://itunes.apple.com/us/app/pacer-pedometer-plus-weight/id600446812?mt=8 ,Sorry ,i'm not good at in English..
- (void)applicationDidEnterBackground:(UIApplication *)application{
if(counter==0){
[player play];
// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
UInt32 doSetProperty = 0;
//The C Style function call
AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (doSetProperty),
&doSetProperty
);
// Activates the audio session.
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[player setDelegate:self];
//play audio
[player play];
[self backgroundHandler];
}
}
Related
I have problem with media play in background mode.
In my app I have to play media play in background mode when server send any notification through socket connection.
In my case media player working fine when app in background mode.
Problem is when app in background mode if I play music app and stop the music player and send notification to my app .Than my app didn't play media player.
I added in plist this one "App plays audio or streams audio/video using AirPlay"
I am using "AVPlayer"
Please help me.
Thanks.
If you look into the AVPlayer documentation it says that it can only play one asset at a time. I think Apple Music uses if not the same API something that is related to this.
AVPlayer is intended for playing a single media asset at a time. The
player instance can be reused to play additional media assets using
its replaceCurrentItem(with:) method, but it manages the playback of
only a single media asset at a time
1). Put this code in you AppDelegate.m (didFinishLaunchingWithOptions) methods :
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
2). After that set Background Modes active for Audio, Airplay and Picture in Picture
Might be, its due to Interruption with current AVplayer running item.
Also, take care you implemented it(Below code)before loading any item to AVPlayer. AND enabled Capabilities to Play audio in background.
NSError *myErr;
[self becomeFirstResponder];
[[UIApplication sharedApplication]beginReceivingRemoteControlEvents];
AVAudioSession *aSession = [AVAudioSession sharedInstance];
[aSession setCategory:AVAudioSessionCategoryPlayback error:&myErr];
[aSession setMode:AVAudioSessionModeDefault error:&myErr];
[aSession setActive: YES error: &myErr];
Implement and Add Interruption handler, so you can re-play your stopped audio after another audio/interruption stopped. and below listener of it will call.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:aSession];
And manage AVplayer play/pause again in it:
- (void)handleAudioSessionInterruption:(NSNotification*)notification {
NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];
switch (interruptionType.unsignedIntegerValue) {
case AVAudioSessionInterruptionTypeBegan:{
// • Audio has stopped, already inactive
// • Change state of UI, etc., to reflect non-playing state
IsInteruptionOccured=YES;
} break;
case AVAudioSessionInterruptionTypeEnded:{
// • Make session active
// • Update user interface
// • AVAudioSessionInterruptionOptionShouldResume option
IsInteruptionOccured=NO;
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here you should continue playback.
// Resume after exteranl interruption.
[_audioPlayer play];
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
// test it with...
NSLog(#"other audio is playing %d",isPlayingWithOthers);
}
} break;
default:
break;
}
}
I'm trying to detect when headphones are plugged into the iPhone. I do this buy the following approach.
//Init the AVAudioSession
-(void)viewDidLoad
{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
}
//Get the current audio session route
-(void)viewWillAppear
{
AVAudioSessionRouteDescription *route = [[AVAudioSession sharedInstance] currentRoute];
}
This works fine and the route.inputs and route.outputs will contain the headphones and the microphone for a wired iPhone headset and will show the built in receiver and built in microphone when the headphones are unplugged. The problem I'm running into is when I press the home button on my app and it moves to the background. When I bring the app back into the foreground the route.inputs is always empty. My question is: Do I need to set the [[AVAudioSession sharedInstance] setActive:NO error: &activiationError] in my appDelegate when applicaionWillResign active is called? Because when route.inputs comes back empty, the headphones are still plugged in and should be detected. Any help would be appreciated. Thank you.
I think a better approach is this :
- (BOOL)isHeadsetPluggedIn
{
AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
for (AVAudioSessionPortDescription* desc in [route outputs])
{
if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])
return YES;
}
return NO;
}
I just tested this and this works even when coming back to foreground from background, and also on viewDiDLoad
Link to Original Answer
I'm developing an iOS application that records audio in background. That's work fine.
The problem is when a call comes in: when i'm calling the app stops to record (that's fine) but when the call ends, I need that the app start to record again.
Is it possible ? How can I do this ?
Thanks to all.
UPDATE
I use AudioQueueNewInput to record audio. Now I'm trying to use this code to get incoming call:
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *categoryError = nil;
[session setActive: NO error: nil];
if (![session setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:&categoryError]){
NSLog(#"Error"); //no error
}
[session setActive: YES error: nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:session];
I can get the ends of call on handleAudioSessionInterruption by AVAudioSessionInterruptionOptionShouldResume, but how can I restart my audio recorder?
I tried to use to call AudioQueueStart again o simply same function that I use to start to record, but I can't see the red bar (mic in use) to know that app is recording. What's wrong ?
Please see this question:
Can not restart an interrupted audio input queue in background mode on iOS
Yes it is possible, but to reactivate the session in the background,
the audio session has to either set AudioSessionProperty
kAudioSessionProperty_OverrideCategoryMixWithOthers
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing);
or the app has to receive remote control command events:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
I have this scenario:
In the background the default iPhone audio player (or any other audio player) is playing some music.
In the foreground my application is running. Then, under certain circumstances, my application has to play audio file (bit like a GPS navigator).
I want my application to pause the background player (ducking is not enough), to play its file and then to continue playing the background player.
Is this possible?
Thank you,
donescamillo#gmail.com
From iOS 6 onwards you can set your audio session active, play your file and then deactivate your session with options using the AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation flag. Make sure you set a non-mixable category when you need to play audio so background audio stops.
In simple steps -
// Configure audio session category and activate ready to output some audio
[[AVAudioSession sharedInstance] setActive:YES error:nil];
// Play some audio, then when completed deactivate the session and notify other sessions
[[AVAudioSession sharedInstance] setActive:NO withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
From Apple's documentation-
When passed in the flags parameter of the setActive:withOptions:error: instance method, indicates that when your audio session deactivates, other audio sessions that had been interrupted by your session can return to their active state.
This flag is used only when deactivating your audio session; that is, when you pass a value of NO in the beActive parameter of the setActive:withOptions:error: instance method
and also-
Deactivating your session will fail if any associated audio objects (such as queues, converters, players or recorders) are currently running.
EDIT: A more detailed example -
Configure a mixable audio session at the start of your applications lifecycle
// deactivate session
BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil];
if (!success) { NSLog(#"deactivationError"); }
// set audio session category AVAudioSessionCategoryPlayAndRecord
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
if (!success) { NSLog(#"setCategoryError"); }
// set audio session mode to default
success = [[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:nil];
if (!success) { NSLog(#"setModeError"); }
// activate audio session
success = [[AVAudioSession sharedInstance] setActive:YES error: nil];
if (!success) { NSLog(#"activationError"); }
When your application wants to output audio without any background audio playing, change the audio session category first like this
// activate a non-mixable session
// set audio session category AVAudioSessionCategoryPlayAndRecord
BOOL success;
AVAudioSessionCategoryOptions AVAudioSessionCategoryOptionsNone = 0;
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionsNone error:nil];
if (!success) { NSLog(#"setCategoryError"); }
// set audio session mode default
success = [[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:nil];
if (!success) { NSLog(#"setModeError"); }
// activate audio session
success = [[AVAudioSession sharedInstance] setActive:YES error: nil];
if (!success) { NSLog(#"activationError"); }
// commence playing audio here...
And when your application has completed playing audio you can deactivate your audio session
// deactivate session and notify other sessions
// check and make sure all playing of audio is stopped before deactivating session...
BOOL success = [[AVAudioSession sharedInstance] setActive:NO withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error: nil];
if (!success) { NSLog(#"deactivationError"); }
I can confirm that the above code works, tested with the Music App playing on an iPhone 5 running iOS 7.0.4, however this is not guaranteed because there are other considerations such as user actions. For example if I plug in a headset the background audio from the music app routes to the headset and continues to play, but if I remove the headset the background audio produced by the music app pauses.
For more info read AVAudioSession Class Reference
Can't make AVQueuePlayer start playing sound queue when it's starting after the app went into the background.
The basic question is: how to start sound from newly created AVQueuePlayer instance from background?
It's for navi-like app that need to play couple of combined sounds with appropriate directions when the time comes. And most of the time the app works in background...
The details are below...
It plays just fine when I start it from active application, and finishes playing sound even after app went to background.
What I did so far:
In AppDelegate inside didFinishLaunchingWithOptions I added:
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
// Change the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);
After the app started I clicked the home button so the app went into the background.
When the time came this code executes (the app is still in background, but note, that I have enabled Audio and AirPlay background mode):
-(void)playTrainingFinishedSound
{
NSMutableArray *queue = [NSMutableArray array];
[queue addObject:[AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:#"alertkoniectreningu" withExtension:#"m4a"]]];
[self initializeAudioPlayerWithQueue:queue];
[self.appDelegate.audioPlayer play];
}
-(void)initializeAudioPlayerWithQueue:(NSArray *)queue
{
self.appDelegate.audioPlayer = [[AVQueuePlayer alloc] initWithItems:queue];
self.appDelegate.audioPlayer.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;
}
Unfortunately this code doesn't make any sound, opposite to the situation when the app was in foreground.
Oh God, there was just one line missing in the AppDelegate didFinishLaunchingWithOptions [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
so it looks now like:
audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
if (audioSession) [audioSession setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
// Change the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);
The reason the AVPlayer is failing is because you can't create/initialize an Audio Unit while an application is in the background, which is what the AVPlayer is attempting to do under the hood. The exception to this rule is of course audio-playing applications which can be started/resumed via the "Play" buttons built into the OS, while they are in the background. Thus, applications which subscribe to remote control events have the capability to start Audio Units in the background, which is why subscribing to these events appears to solve the problem.
It's unclear whether Apple is OK with using the API feature in this way.