I'm developing a VOIP app that allows people to make VOIP calls. Whenever a user is in a VOIP call and receives a native call on their phone the audio of the VOIP app stops working.
I've read that one must reinitialize the AudioSession and I'm doing so with this block of code but this is not working. Any suggestions?
self.callCenter = [[CTCallCenter alloc] init];
[self handleCall];
- (void)handleCall
{
AVAudioSession *session = [AVAudioSession sharedInstance];
self.callCenter.callEventHandler = ^(CTCall *call){
if ([call.callState isEqualToString: CTCallStateConnected])
{
}
else if ([call.callState isEqualToString: CTCallStateDialing])
{
}
else if ([call.callState isEqualToString: CTCallStateDisconnected])
{
NSLog(#"Call ended");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[session setActive:YES error:nil];
});
}
else if ([call.callState isEqualToString: CTCallStateIncoming])
{
NSLog(#"Call received");
}
};
}
I have worked on VoIP App with SIP library using. If you are also using same library, while getting native call if your VoIP call already existed, then native call terminate your VoIP call audio session. So, while getting native call, just make "Mute" your SIP library and after ended the native call, just "UnMute" thats it.
pjsua_conf_adjust_rx_level(0 /* pjsua_conf_port_id slot*/, 0.0f); //for mute the audio
pjsua_conf_adjust_rx_level(0 /* pjsua_conf_port_id slot*/, 1.0f); //for unmute the audio.
I hope this will help you.
Related
Issue:
My application's audio is not resuming after an interruption (such as phone call or when I use other applications). This issue happens when my application is already in the background state before the interrupt occurs.
Code to handle interrupts:
- (void)handleInterruption:(NSNotification *) notification{
if (notification.name != AVAudioSessionInterruptionNotification || notification.userInfo == nil) {
return;
}
NSDictionary *info = notification.userInfo;
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
if ([[info valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
NSLog(#"InterruptionTypeBegan");
} else {
NSLog(#"InterruptionTypeEnded");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSLog(#"playing audio");
self->_audioPlayer.numberOfLoops = -1;
[self->_audioPlayer play];
});
}
}
}
In Xcode console, I see logs in the following sequence but no audio is played:
InterruptionTypeBegan
InterruptionTypeEnded
playing audio
I would appreciate any suggestions and thoughts on this topic. Thank you.
EDIT:
I have noticed the same issue with many online music streaming apps such as Saavn and Spotify.
I have a video camera app and I would like it to allow users to capture content while on the phone.
I can do this by disconnecting the audio capture when the phone call is received and the session is interrupted, but because the session is no longer interrupted, I now have no way of knowing when the phone call ends and it is ok to reconnect the audio device.
If I use this callbacks for AVCaptureSessionWasInterruptedNotification and AVCaptureSessionInterruptionEndedNotification:
- (void)sessionWasInterrupted:(NSNotification *)notification {
NSLog(#"session was interrupted");
// disconnect the audio device when a call is started
AVCaptureDevice *device = [[self audioInput] device];
if ([device hasMediaType:AVMediaTypeAudio]) {
[[self session] removeInput:[self audioInput]];
[self setAudioInput:nil];
}
}
- (void)sessionInterruptionEnded:(NSNotification *)notification {
NSLog(#"session interuption ended");
// reconnect the audio device when the call ends
// PROBLEM: disconnecting the audio device triggers this callback before the phone call ends...
AVCaptureDevice *device = [[self audioInput] device];
if ([device hasMediaType:AVMediaTypeAudio]) {
if ([[self session] canAddInput:[self audioInput]])
[[self session] addInput:[self audioInput]];
}
}
I get an infinite loop of both of them being called one after another for the entire duration of the phone call and the camera is frozen. If I don't reconnect the device in the second function, the camera keeps working, but sessionInterruptionEnded is not called again when the phone call ends.
Is there a callback for when the phone call ends?
I want to play a song through speaker while being able to receive a video call using Quickblox.
My audio rates are getting messed up.
And also a bigger a problem is when the call ends quickblox framework sets audio session to deactivated state. i.e
[Avaudiosession sharedInstance]setActive:NO....
How do I stop this from happening?
Or is there a way the above mentioned scenario can be handled.??
I have read through google for a month now and still didn't find any suitable answers or any guidelines.
Can anyone help me with this problem/??
First, to allow AVAudioSession to work with other AVAudioSessions, you'll need to set up the option AVAudioSessionCategoryOptionMixWithOthers when initializing it:
NSError *sessionError = NULL;
BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:&sessionError];
if(!success) {
NSLog(#"Error setting category Audio Session: %#", [sessionError localizedDescription]);
}
To handle interruptions (a call, alarm, etc..), you should set up an observer for interruptions to the NSNotificationCenter where you'll be able to handle the activation/deactivation of the AVAudioSession if necessary:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
The NSNotification will carry the Type of Interruption and Key:
- (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
NSLog(#"AVAudioSessionInterruptionTypeBegan");
} break;
case AVAudioSessionInterruptionTypeEnded:{
// • Make session active
// • Update user interface
// • AVAudioSessionInterruptionOptionShouldResume option
NSLog(#"AVAudioSessionInterruptionTypeEnded");
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here you should continue playback.
}
} 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.
So I have a music app that uses an AVAudioSession to allow it to play when it is in the background. I use this call:
[audioSession setActive:YES
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
My problem now is if I go to another app and it steals the audio session (thus now stopping music playback from my app and playing something else), and I come back to my app, no matter what I do to reset my audio session or my audio units, my app's sound is gone.
Does anyone know what to do?
So after registering for the AVAudioSession notifications:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:aSession];
You need to resume/restart you need to restart your player in the handler interruption type is AVAudioSessionInterruptionTypeEnded:
- (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
} break;
case AVAudioSessionInterruptionTypeEnded:{
// • Make session active
// • Update user interface
// • AVAudioSessionInterruptionOptionShouldResume option
if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) {
// Here you should continue playback.
[player play];
}
} break;
default:
break;
}
}
You can see a complete explanation here: AVplayer resuming after incoming call