iOS Audio Playback Over Phone Call - ios

I've found a few related questions for Android but nothing for iOS.
Is there any possible way to override the phone's microphone once a phone call has been received and playback an audio file over the phone call? If it's not possible to override the microphone, is there a way to mix in an audio file along with the microphone?

I don't believe you can do what you're wanting. From Apple's Audio Session Programming Guide:
The system follows the inviolable rule that “the phone always wins.” No app, no matter how vehemently it demands priority, can trump the phone. When a call arrives, the user gets notified and your app is interrupted—no matter what audio operation you have in progress and no matter what category you have set.
Which, if you think about it, makes sense: A user is unlikely to want unexpected audio to interrupt or overlay a phone conversation.

Related

How do I know that an audio interruption ended without receiving AVAudioSessionInterruptionTypeEnded?

I'm using AVAudioSession in my VOIP app (using also CallKit).
I understand that the session can get interrupted by a number of things, for example by a second incoming call.
Apple states towards the bottom of this page:
https://developer.apple.com/library/content/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/HandlingAudioInterruptions/HandlingAudioInterruptions.html#//apple_ref/doc/uid/TP40007875-CH4-SW5
"Note: There is no guarantee that a begin interruption will have a
corresponding end interruption. Your app needs to be aware of a switch
to a foreground running state or the user pressing a Play button. In
either case, determine whether your app should reactivate its audio
session."
On the mentioned page there is an example for a special case, when the user ignores the incoming call and in that case AVAudioSessionInterruptionTypeEnded is being sent.
But what should I do to know when the interruption has ended in every other case (in which cases I will never receive an AVAudioSessionInterruptionTypeEnded)? (E.g. When the user answers the 2nd call and puts me on hold and later he ends the 2nd call?)
Thanks!
I remember when you use CallKit, no app using audio like music will interrupt your app except for those other voip apps or native calls.
In that case, your call will be ended/held according to your response on the call kit ui (If your call do not support held, you will not be shown a thid button accept&hold)----Then, you can get your callback from CallKit delegate methods.
The Interruption api just works when CallKit is not used and CallKit app have a higher priority on audio session than those not using it.

Reroute Audio to Bluetooth Speaker

I am creating a Video & Audio capturing app. Every time I start to record, the music played in the bluetooth speaker plays in the phone's speaker. When I exit the app, the music comes back playing on the bluetooth speaker.
My first attempt to solve this is to provide the necessary options for the audioSession, like this:
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: [AVAudioSessionCategoryOptions.MixWithOthers, AVAudioSessionCategoryOptions.AllowBluetooth])
But that didn't work. So my second solution that I'm thinking is to reroute the music output again to the bluetooth speaker.
I researched on this and found this function: audioSession.setOutputDataSource
I don't really know the parameters to be passed there.
And I am not really sure if in the moment I started the video recording, the phone/or my code disables the bluetooth connection or it just reroutes the playback to the phone's speaker.
UPDATE: I coommented out this line: // try audioSession.setMode(AVAudioSessionModeMoviePlayback) and the music pauses a bit and plays again on the bluetooth speaker. But the problem here is that the captured video has no audio.
UPDATE 2: Would this question have a solution if I provide you with my code?
I'll go ahead and take a shot at answering the original question. From Apple
s documentation I go this:
func setOutputDataSource(_ dataSource: AVAudioSessionDataSourceDescription?)throws
Parameters dataSource
The data source for the audio session’s output.
outError
On input, a pointer to an error object. If an error occurs, the pointer is set to an NSError object that describes the
error. If you do not want error information, pass in nil. here
This page should help you figure out what the AV Session data source description does/returns, but in summery it:
You obtain data source descriptions from the shared AVAudioSession object or the AVAudioSessionPortDescription objects corresponding to its input and output ports. Only built-in microphone ports on certain devices support the location, orientation, and polar pattern properties; if a port does not support these features, the value of its dataSources property is nil. here
Are you trying to route music from your app to the speaker (is that the music playing?) or is the music coming from another app, and you would like a dual output?
For error checking you could make sure the speaker is still available, using something like the output data source. If it returns nill (null.) it means you are not able to switch between data-sources.
It's probably also worth noting the user must give you permission to record, however I doubt this is the problem as you seem to have already been recording at one point, just when it was playing through the phone, not the speaker

change output speaker when user move his phone

My app lets the user hear sound files, and im using AVAudioPlayer to play it.
I saw in some apps a very nice behaviour where the sound speakers changes from regular speakers to the ear speakers when the user put his phone next to his ear.
I have now idea where to start here, should i detect the phone's movement and change the output speaker or is there any native implementation for this behaviour?
The most straightforward path to accomplishing this is to use proximity monitoring in UIDevice. Proximity monitoring tells you whether the phone is close to the user or not.
Listen for UIDeviceOrientationDidChangeNotification and react to proximityState changes accordingly — in your case, rerouting audio.
There's a thorough answer to a similar question here. That answer includes supplementary details to combine device motion for increased accuracy.
What you're looking for is the proximity sensor (that little piece of hardware near the iphone ear speaker), and not any motion sensing mechanism. The proximity sensor is accessible via the public API through the UIDevice's proximityState property, which simply returns a boolean value indicating whether the sensor is close to the user or not: proximityState.
Based on that value, you can then proceed to routing your audio to the ear speaker. This can be achieved using the AVAudioSession class and specifically setting the category (setCategory:error) to AVAudioSessionCategoryPlayAndRecord.

How can I start a process when this play symbol comes up

In my app I am streaming audio and there is a period of 5-10 sec depending on the connection where the buffer is loading and after this, my app starts to play the audio. When it starts to play the audio this symbol comes up in the screen.
Here is an image of what im talking about.
http://img27.imageshack.us/img27/3667/img0596.png
I want to change a label in my app when this symbol comes up in the screen, but i dont know which function let me detect this.
The symbol is the "Play" button common to music devices. There is most likely an NSNotification center message that can be "listened for". However, depending on how you are buffering your sounds there is probably a delegate that can notify a selector once it has begun playback. Without more details I can not give more detailed advice. If I were in your position I would take a very hard look at the API you are utilizing, most likely several methods exist to either post notification or send delegate messages notifying the state of the stream as well as playback. I have worked with some streaming audio API and I was able to get status of the buffer as well many other messages from the stream object(s). These are just part of good design, so most likely it is there.

How to handle AVPlayer errors while the app is running in the background?

I am using AVPlayer to play an audio stream, and it's possible to keep it playing in the background. I'm wondering how could I handle a situtation where the user loses internet connectivity, so that I could provide some feedback or maybe try to re-establish the playback after some seconds.
EDIT: I know that the question regards AVPlayer, but if you have an answer with MPMoviePlayerController it might be useful as well. Right now, by using MPMoviePlayerController, I'm trying to get the MPMovieFinishReasonPlaybackError case of the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey, by subscribing to the MPMoviePlayerPlaybackDidFinishNotification but if f.e. my audio is playing in the background and I turn airplane mode on, I never get this notification; I only get MPMovieFinishReasonPlaybackEnded, and I don't know how to separate that from the case that the user stops the audio himself.
I tried looking around for the actual source but I remember reading somewhere that if the audio playback stops (for whatever reason) it kills the background thread. The person writing about the issue talked about possible feeding the stream some empty audio content to keep the thread alive. You might be able to send a local notification from a call back error notifying the user that the audio experienced an error and will have to be manually restarted from within the application. Haven't played around with the API enough to know which callback is the best one to use in this case. If I find the link I'm looking for I'll update.
EDIT: Here's Grant Pannell's take on audio streaming and multitasking.

Resources