KeithB
KeithB

Reputation: 541

Does iOS Reduce Speaker Volume for Apps Using a Microphone?

I am developing an Xcode/Swift/SwiftUI app for real-time music visualization. I allow the user to push a button to toggle between microphone-input and file-play input (but never both at the same time). My app runs fine on my Mac and on my iPad, but on my iPhone, the speaker audio is only at half-volume (and appears to be only coming from the back speakers) - even when I am in file-play mode. I have traced the problem to one offending line in my code - namely the declaration

let mic = engine.inputNode // where engine = AVAudioEngine()

When I comment-out this line, the iPhone speaker level (for file-play mode) is fine. But when I un-comment it, the iPhone speaker level is barely audible. Even when I wrap this line inside a conditional if(micEnabled){} construct, the sound level is fine at first; but as soon as I select the microphone and then toggle back to file-play, the volume again decreases.

I suspect that iOS detects when a microphone is declared and automatically reduces the speaker volume to avoid audio feedback. This would make sense because nobody wants music playing when they are speaking on a telephone call. But it would also make sense to provide developers a way to override this feature if they want to handle it themselves. In my case, for the microphone-input case, I purposely assign the audio stream a zero-volume after it is tapped and before going to the speaker.

My source code is available here. All of the audio code is inside the MuVis / Shared / AudioManager.swift class.

Can anyone help me to get the file-play mode to work with full volume on my iPhone - while also allowing the user the option to select microphone-input mode?

Upvotes: 0

Views: 1461

Answers (1)

KeithB
KeithB

Reputation: 541

Many thanks to Rob Napier for pointing me in the right direction for solving my problem.

As a macOS-only developer, I had ignored AVAudioSession (since it caused compiler errors on macOS). When I converted my MuVis app from macOS-only to multiplatform, I simply started a new Xcode project with the appropriate multiplatform settings, and then pasted my existing code into the shared folder. After cleaning up a few errors (mostly calls to NSObject), it magically worked on all Apple platforms - except for the iPhone audio problem described in my question. After a little research and a lot of trial-and-error, I found that my audio-volume problem is solved by inserting the following code into my setupAudio() function:

    #if os(iOS)
        // For iOS devices, set the audioSession category, mode, and options:
        let session = AVAudioSession.sharedInstance()  // Get the singleton instance of an AVAudioSession.
        do {
            if(filePlayEnabled) {
                // This is required by iOS to prevent output audio from going only to the iPhone's rear speaker.
                try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.default, options: [.defaultToSpeaker])
            }
            else {
                try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.default, options: [])
            }
        } catch { print("Failed to set audioSession category.") }
    #endif

Again, thank you Rob.

Upvotes: 1

Related Questions