iOS Volume only adjustable on Playback - ios

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.

Related

App with playback audio category stops other apps sound

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.

AVPlayer doesn't respond to commands from bluetooth device

My ios app uses AVQueuePlayer to play audio.
The play/pause controls work properly from Control Center and from ios lock screen, but not for commands invoked from bluetooth device. E.g., the callbacks in my app are never invoked when double-tapping airpods or other third-party bluetooth headphones.
I'm running on an iphone 8 plus device with iOS 15.
I'm using https://developer.apple.com/documentation/avfoundation/media_playback_and_selection/creating_a_basic_video_player_ios_and_tvos/controlling_background_audio.
On app startup, it sets up the audio session like this:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playAndRecord,
mode: .spokenAudio,
options: [
.allowBluetooth,
.defaultToSpeaker
])
try audioSession.setActive(true)
The app listens for play/pause events like this.
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.addTarget { event in
print("play")
return .success
}
commandCenter.pauseCommand.addTarget { event in
print("pause")
return .success
}
commandCenter.togglePlayPauseCommand.addTarget { event in
print("toggleplaypause")
return .success
}
Playback works correctly through all bluetooth devices. On lock screen or control center, play/pause cause "play" and "pause" to get printed. But nothing is printed when tapping airpods. (Tapping airpods works fine in any other audio app.)
Any ideas what might be missing?
Found the solution. Airpod controls started working when I changed the mode to .playback. Apparently they don't work with .playAndRecord. I also needed to remove the .allowBluetooth, which is not compatible with .playback mode.
For my app, since I need to both play and record, I will set the mode to .playAndRecord when the user needs to record, and otherwise keep it in .playback.

iPhone Screen recording failed to save due to -5825

I've video streaming in my app. I'm having some weird issues in screen recording on iPhone. The most obvious issue is that during live streaming screen recording iPhone fails to save recorded screen with error 5825.
Another issue is that audio stops in my app when screen recording is started. I can screen record other apps such as YouTube etc.
Somewhere it's suggested that it's due to lack of storage. I've enough storage space on my devices. I've tried different iPhones and I can see same issue on all.
So I was wondering if I need any special permissions or any handling in my app to allow screen recording?
Is it really any issue with my app (code) or it's purely device issue?
Have you tried to set AVAudioSession category to .multiRoute or .playAndRecord?
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.multiRoute)
try session.setMode(.default /* or .moviePlayback*/)
try session.setActive(true, options: options)
} catch {
print("ActiveAudioSession failed.")
}
I have the same issue but can't always reproduce it, so my next try is to add this lines of code.
Another thing I found here - https://discussions.apple.com/thread/251342404
which says:
That usually appears when there is a space issue. Do you have ample free space on the iPhone? How long of a screen recording was it? Did you attempt to record any copyrighted materials?
UPDATE
seems to be it could be also a bug in iOS 14+

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

AVAudioEngine changes other app's output route

I'm seeing an unexpected effect with AVAudioEngine that I'm trying to get my head around. The route of another app's audio playback changes from the speaker to the earpiece when my app's engine starts. I want the other app to keep playing out of the speaker.
Here's how to reproduce.
Make an empty app and add the UnexpectedAudio class below. In your ViewController class add and initialize an unexpected property (let unexpected = UnexpectedAudio()), and then add a button to your storyboard that calls unexpected.start().
class UnexpectedAudio {
let engine: AVAudioEngine
init() {
self.engine = AVAudioEngine()
_ = engine.inputNode // lazily creates node
}
func start() {
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord,
mode:AVAudioSessionModeDefault,
options: [.mixWithOthers])
try! engine.start()
}
}
Run the app, but don't press the button yet. Then with no headphones plugged in, jump over to Apple Music and play a song. It should come out the speaker. Now, switch back to your app and press the button. For me, this makes the Apple Music audio switch back to the earpiece.
Any idea why this might be happening? And how I can prevent the route change? Thanks!

Resources