App with playback audio category stops other apps sound - ios

I added radio functionality to my application recently.
I wanted it to play music even when it is in the background.
So I implemented this piece of code
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: [.duckOthers, .allowBluetooth])
try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError {
print(error)
}
I got the app to play music when in the background now but the problem is that the app stops all other app's sounds when launched.
For example when SoundCloud is playing music and when I launch my app Soundcloud stops the music.
What I want to achieve is to make my app play music when it is in the background and also allow other apps to play music when my app is not playing music.
How can I fix that issue?
Thanks

do {
try AVAudioSession.sharedInstance().setCategory(.ambient)
try AVAudioSession.sharedInstance().setActive(true)
} catch { print(error) }
Above code add in AppDelegate.swift files didFinishLaunchingwithOptions method. This will solve your problem

To partially answer your question, you can allow your app to play audio while other apps are playing audio with the following configuration:
do {
try AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
} catch(let error) {
print(error.localizedDescription)
}
.playback means the audio playing is central to the use of your app. So if you're playing music, background sounds like white noise, etc. you probably are using playback mode. .mixWithOthers is 'An option that indicates whether audio from this session mixes with audio from active sessions in other audio apps.' - in other words allows your primary audio to mix with audio coming from other apps.
The one thing I haven't figured out - is why on the first launch of my app other background audio pauses. Subsequent launches seem to work fine.

Related

How do I make AVAudioSession work in silent mode and with .mixWithOthers

I'm writing an iOS app in Swift (Xcode 11.5) using AVAudioEngine
It's all working fine, but I can't get it to play along with other audio apps when the iPhone/iPad has the mute button off.
With this:
try AVAudioSession.sharedInstance().setCategory(.playback)
my audio works with the mute button on or off, but if I'm playing something from Apple Music, when I hit play on my audio, Apple Music pauses.
With this:
try AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
my audio works with Apple Music, but doesn't play if the mute button is off.
With this:
try AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers])
having .mixWithOthers makes no difference.
I'm sure there is a combination of options that will make it work with the mute button on or off and not stop other audio playing, but I can't find it!
TIA for any suggestions.
Ian
I've figured this out and, as pointed out by matt, I was doing something wrong! I can't post my code here because it is pretty big. Basically, I've written and audio class that handles all the audio files, declares the engine, AVAudioEngine(); nodes, AVAudioPlayerNode(); and does all the playing and so on.
My mistake was to put this sort of stuff in that class, and it was obviously the wrong place:
do {
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setActive(false)
if resetOptions.muteOtherApps {
try audioSession.setCategory(.playback, options: [])
} else {
try audioSession.setCategory(.playback, options: [.mixWithOthers])
}
} catch {
print("Audio error")
}
Since I'm letting the user choose between these options, it was convenient for me to put it in my main ViewController class. However, if it's set fixed for the app, from what I've read a good place to put it is in AppDelegate.Swift in the didFinishLaunchingWithOptions function.
The main point, at least what worked for me, is to keep these things separate to the class that is actually managing the audio.
So, thanks Matt.
Ian

Does having FaceID or touchID in your app when app enters background stop audio playing in background?

I have a Biometrics for FaceID/TouchID that activities whenever the app enters background. I already have the app configured to play audio in the background, but FaceID/TouchID seems to stop all background activity, such as audio. Is this the case?
By default, audio is always stopped when entering the background. To enable it, you must configure your app Capabilities.
Click on your app target > Capabilites > Background Modes
then set on Audio, Airplay, and Picture in Picture.
Add this code on the line before the audio is played:
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay]) // enable player back
try AVAudioSession.sharedInstance().setActive(true) // set session to active
} catch {
print(error)
}
Also check the Background fetch mode in capabilities.
Short answer yes it does. If FaceID and TouchID is activated at AppDidEnterBackground; basically whenever the user leaves the app, it will stop the audio. Has not nothing to do with background fetch since the audio file was already downloaded. codeherk's answer is accurate if anyone is looking for how to play audio in the background.

iOS ReplayKit stop recording microphone if i play AVPlayer during recording

i am using ReplayKit's RPScreenRecorder.shared().startCapture method to record screen and microphone, but i am facing an issue. if i play AVPlayer while ScreenRecording, the microphone stops recording audio. Below are two scenario. in first everything working fine but in second voice recording not working.
started AVPlayer and then start screenRecording, AVPlayer's Audio stop and my screen and microphone start recording
started screenRecording and working fine. then i start the AVPlayer and when AVPlayer play the audio the voice recording is stopped
After digging a lot i found a solution. Default AVFoundation Allow to use either Microphone or Speaker at a time and ReplayKit is incompatible with AVPlayer content. So if we want to use both of them at a time we need to set AVAudioSession's Category to AVAudioSessionCategoryMultiRoute.
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryMultiRoute)
} catch let error as NSError {
print(error)
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError {
print(error)
}
I think it is a system limitation
As in apple official documents it is written
ReplayKit is incompatible with AVPlayer content.
You can read details here

How can I prevent video recording with AVFoundation from interrupting any global audio that is currently playing (Swift)?

I have successfully implemented valid and working AVFoundation video recording functionality into my application. That said, any playing audio e.g. Apple Music or a YouTube video playing in the background is interrupted / immediately paused whenever the video recording begins.
My question is: How could I allow the globally-playing audio to continue to play without interruption when recording video?
I was able to do this by adapting the answer here to Swift.
I was doing this to prevent a silent tutorial video in my app from interrupting any currently playing audio. Setting the AVAudioSession category to "ambient" using the setCategory(_:mode:options:) method seems to be the key here.
Apple seems to suggest using this method within the application didFinishLaunchingWithOptions method, but I think their example is targeted towards audio apps. So depending on your needs, you may want to put it there.
Here's the adapted code, I placed it within the view controller that is showing the video:
import AVFoundation
...
override func viewDidLoad() {
super.viewDidLoad()
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.ambient, mode: .default, options: .mixWithOthers)
} catch {
print(error.localizedDescription)
}
}

iOS Volume only adjustable on Playback

Developing an iOS app which plays back audio messages in segments (not continuous playback). When the app is opened, I initialize the audio session with the following options.
func _initAudioSesh() {
let audioSession = AVAudioSession.sharedInstance()
do {
if #available(iOS 10.0, *) {
try audioSession.setCategory(
AVAudioSessionCategoryPlayAndRecord,
mode: AVAudioSessionModeVoiceChat,
options: [
AVAudioSessionCategoryOptions.defaultToSpeaker,
AVAudioSessionCategoryOptions.allowBluetooth,
AVAudioSessionCategoryOptions.allowBluetoothA2DP
]
)
} else {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
}
} catch {
print("Setting category to AVAudioSessionCategoryPlayback failed.")
}
}
Then, when ready to playback audio, I grab focus using setActive(true) and release focus using setActive(false)
The issue I'm encountering is that in the app, the hardware volume buttons only work when audio is playing, otherwise, the buttons do nothing. I was able to hack around this by ALWAYS holding setActive(true), but that hack is ugly and causes other issues. Has anyone else experienced volume buttons not working/adjusting in-app, and only working when audio is actively being played?
As soon as I leave the app, audio adjustment works, as soon as I bring it back into focus, it stops working unless I begin to play audio.
I've tried messing with how & when I create the audio session, with no success.
This ended up being a result of a specific library we're using (react-native-system-settings), which has now been patched. If other users encounter issues, the fix seems to be around allowing UI to show in VolumeView. Otherwise, it doesn't allow the hardware buttons to affect volume.

Resources