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];
Related
My app both records with and asks permission to use, background recording. I enjoy the red status bar while recording despite the fact that no one else seems to. My problem is turning it off...
This is the code I use when I am finished with the recording process:
- (void)stopRecording {
[self.recorder pause];
[self.recorder stop];
self.recorder = nil;
[self.audioSession setActive:NO error:nil];
self.audioSession = nil;
}
I want this red bar to be gone once the recording is done (or at least shortly thereafter) to let the user know it has finished. Obviously it refuses and a quick Google search will show that a number of other people have had similar problems. Can anyone tell me what the solution is because I have at least 2 apps I have found that respond properly to stopping a recording and shutting it off at an appropriate time.
Turns out I was missing just a few lines of code... here they are:
- (void)stopRecording {
[self.recorder pause];
[self.recorder stop];
self.recorder = nil;
[self.audioSession setActive:NO error:nil];
[self.audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
self.audioSession = nil;
}
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;
}
}
Sorry for a long introduction of the problem.
In my app I am using recording audio and set category to record
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryRecord error:&err];
When an ad network shows interstitial ad, after that recording is all mute (there is no sound in recording). As this happens with users on live network only, I am not able to reproduce it at my end.
In the log I get ">>>> frameSizeChanged = 4096" from users which points to webkit code
https://github.com/WebKit/webkit/blob/master/Source/WebCore/platform/audio/ios/AudioDestinationIOS.cpp
This looks like some process is holding on to Audio Unit setup and not letting it go even after it is completed(freed / released).
Question: Is there a way to clean up audio unit setup by some other module? Just need to reset so that recording can work again in app after the ad is shown.
I have tried to capture "AVAudioSessionInterruptionNotification" but there is none. Any help is really appreciated
You need to handle your audio system getting interrupted. Many things can cause your audio to get interrupted:
- Receive a phone call while your app runs
- Other app running uses audio
- iOS needs to play a sound
- etc
Your app needs to detect this interruption as your app's audio session will be essentially muted. Once the interruption is done, you need to restart your session.
Set up your listener as the first step in your session setup
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(yourInterruptionListener:) name:AVAudioSessionInterruptionNotification object:nil];
In your interruption listener, handle the cases of getting interrupted and handle restarting your session
-(void) yourInterruptionListener:(NSNotification*) aNotification
{
NSLog(#"Interruption happened");
NSDictionary *interruptionDict = aNotification.userInfo;
NSNumber* interruptionTypeValue = [interruptionDict valueForKey:AVAudioSessionInterruptionTypeKey];
NSUInteger interruptionType = [interruptionTypeValue intValue];
if ( interruptionType == AVAudioSessionInterruptionTypeBegan)
{
// stop your audio session here
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *errorInAudio = nil;
[session setActive:NO error:&errorInAudio];
}
else if ( interruptionType == AVAudioSessionInterruptionTypeEnded )
{
// Your interruption ended, restart the session
// call or paste your session startup code here
}
else if ( interruptionType == AVAudioSessionInterruptionOptionShouldResume )
{
}
else
{
NSLog(#"Some other interruption");
}
}
If you need to simulate the behavior of your users, start your app then call your self from a different phone. It will definitely interrupt your audio.
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.
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];
}
}