Audiokit: AKMicrophone crash init in 4.5.5 version

Created on 10 Dec 2018  路  30Comments  路  Source: AudioKit/AudioKit

AudioKit version 4.5.5: crash in code
AKSettings.audioInputEnabled = true
mic = AKMicrophone()
tracker = AKFrequencyTracker(mic)
silence = AKBooster(tracker, gain: 0)

_AVAE_Check: required condition is false: [AVAudioIONodeImpl.mm:911:SetOutputFormat: (format.sampleRate == hwFormat.sampleRate)] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: format.sampleRate == hwFormat.sampleRate'

Test device - iPhone 8 and simulators
AudioKit.engine.inputNode.inputFormat(forBus: 0).sampleRate periodically returns in the application 44100.0 or 48000.0

On the iPhone se AKMicrophone() works stably, no crash

Most helpful comment

A lot of this is being revamped and should be fixed in an upcoming version of AudioKit.

All 30 comments

This bug is repeated when trying to create a second AKMicrophone() for a period of time. AudioKit.engine.inputNode.inputFormat(forBus: 0).sampleRate changes from 48000 to 44100 after stopping the first AKMicrophone

AKMicrophone() crash in iOS 11.4

0. Crashed: com.apple.main-thread

0 0x102fbe94c specialized AKMicrophone.getFormatForDevice() (AKMicrophone.swift:93)
1 0x102fbdcb8 AKMicrophone.init() ()
2 0x102fbe068 @objc AKMicrophone.init() ()

A lot of this is being revamped and should be fixed in an upcoming version of AudioKit.

There is there is potentially dangerous code in func getFormatForDevice() of class AKMicrophone.swift, which was committed 24 days ago.

private func getFormatForDevice() -> AVAudioFormat? {
    var channelCount: UInt32 = 2
    #if os(iOS) && !targetEnvironment(simulator)
    channelCount = AudioKit.engine.inputNode.inputFormat(forBus: 0).channelCount
    let currentFormat = AudioKit.engine.inputNode.inputFormat(forBus: 0)
    let desiredFS = AudioKit.deviceSampleRate
    return AVAudioFormat(commonFormat: currentFormat.commonFormat,
                         sampleRate: desiredFS,
                         interleaved: currentFormat.isInterleaved,
                         channelLayout: currentFormat.channelLayout!)
    #else
    let desiredFS = AKSettings.sampleRate

    return AVAudioFormat(standardFormatWithSampleRate: desiredFS, channels: 2)
    #endif
    return AVAudioFormat(standardFormatWithSampleRate: desiredFS, channels: channelCount)
}

please look at currentFormat.channelLayout!
Is it save to use explicit unwrapping here?

have had the same crash in 4.5.5 as well. What I found that 4.5.5 works well on iPhone 5s and 6 however crashes on iPhone 8 and X. Downgrading AudioKit to 4.5.2 works in my case.

It's not fixed in 4.5.5:
screenshot 2018-12-23 at 03 40 03

@NBelfast same crash on 4.5.2.

Anybody find any workarounds for this? This is the last major bug with my app affecting about 3% of users...

Not sure if it's true, but according to the code we should do following:

AKSettings.audioInputEnabled = true
try? AudioKit.start()
mic = AKMicrophone()

@bernikowich thanks, for now I've tried submitting a new version that replaces the getFormatForDevice() function with one that safely sets the channelLayout parameter

getting same error on 'AKMicrophone()'. I am using xcode 10(cocoapod 4.5.5). please fix this

I've downgraded to 4.5.4 until I see mention of an AKMicrophone fix. Is there an ETA on when those fixes will go live?

@davidjaystrauss So 4.5.4 works but 4.5.5 doesn't? @bernikowich said it was happening in 4.5.2. I guess I am just not clear on what to fix. We're revamping all of the hardware integration stuff, but I don't want you all to have to wait on that.

@aure it seems that there's still a crash in mic init() but possibly not in the same place. Fabric is showing me that it's crashing on connect to the AVAudio engine, whereas I believe the 4.5.5 crash is in getFormat correct? Either way, it seems the crash is still present although maybe not quite as volatile as in 4.5.5, with only one reported crash in the last couple weeks.

Not sure if this is helpful, but figured I would drop my two cents in case it's helpful to someone.

I started getting this same crash with 4.5.4 - 4.5.6 when I added the line below in a different view controller prior to a segue into another view controller that called

mic = AKMicrophone()
...
AudioKit.start()

try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])

I added the line above mainly just to allow for playback of video sound when the phone was in silent mode.

Once I removed that line, everything is working again, but only tested taking it out with 4.5.6.

Does anybody know how to duplicate this error? I have tried numerous things in the setup of the audio engine, but haven't found a fix yet--or a way to reproduce... code below, which is called inside a viewDidLoad function of a UIViewController:

AKSettings.audioInputEnabled = true
AKSettings.bufferLength = .medium
AKSettings.defaultToSpeaker = true

let session = AVAudioSession.sharedInstance()
AKSettings.sampleRate = session.sampleRate
player = AKPlayer()

mic = AKMicrophone() // crashes here occasionally for 4% of users
micMixer = AKMixer(mic)
boostedMic = AKBooster(micMixer, gain: 5)
amplitudeTracker = AKAmplitudeTracker(boostedMic)
micSilencer = AKBooster(amplitudeTracker, gain: 0)

playerAmplitudeTracker = AKAmplitudeTracker(player)
pitchNode = AKTimePitch(playerAmplitudeTracker)
outputMixer = AKMixer(micSilencer, pitchNode)
AudioKit.output = outputMixer

startEngine()

Crash: AKMicrophone.swift - Line 93
specialized AKMicrophone.getFormatForDevice()

My APP is experiencing something similar, but Im not able to reproduce it personally. It's a definitely happening since I'm getting crash from about 1% of DAUs.

Here is the AKSettings I have configured:

let input = AudioKit.engine.inputNode
        let bus = 0
        let inputFormat = input.outputFormat(forBus: bus)
        AKSettings.sampleRate = inputFormat.sampleRate
        AKSettings.channelCount = inputFormat.channelCount
        AKSettings.defaultToSpeaker = true
        AKSettings.audioInputEnabled = true
        AKSettings.useBluetooth = true
        AKSettings.bufferLength = .medium
        AKSettings.enableLogging = true

Stack trace. Hope it will help the investigation:
Fatal Exception: com.apple.coreaudio.avfaudio required condition is false: format.sampleRate == hwFormat.sampleRate

Fatal Exception: com.apple.coreaudio.avfaudio
0  CoreFoundation                 0x1ca8c3ec4 __exceptionPreprocess
1  libobjc.A.dylib                0x1c9a94a40 objc_exception_throw
2  CoreFoundation                 0x1ca7d9b3c +[_CFXNotificationTokenRegistration keyCallbacks]
3  AVFAudio                       0x1d07d460c AVAE_RaiseException(NSString*, ...)
4  AVFAudio                       0x1d07d3c2c _AVAE_Check(char const*, int, char const*, char const*, bool)
5  AVFAudio                       0x1d0879650 AVAudioIONodeImpl::SetOutputFormat(unsigned long, AVAudioFormat*)
6  AVFAudio                       0x1d0805958 AVAudioEngineGraph::_Connect(AVAudioNodeImplBase*, AVAudioNodeImplBase*, unsigned int, unsigned int, AVAudioFormat*)
7  AVFAudio                       0x1d0881648 AVAudioEngineImpl::Connect(AVAudioNode*, AVAudioNode*, unsigned long, unsigned long, AVAudioFormat*)
8  AVFAudio                       0x1d08816d0 -[AVAudioEngine connect:to:format:]
9  Lookwide                       0x100604c44 AKMicrophone.init() (<compiler-generated>)
10 Lookwide                       0x100604cb0 @objc AKMicrophone.init() (<compiler-generated>)
11 Lookwide                       0x100272bf4 AudioKitManager.init() (AudioKitManager.swift:167)
12 Lookwide                       0x1002703a8 $S8Lookwide15AudioKitManagerC06sharedD033_CB25F120035AD99142715FCFE02DB161LLACvpZfiACyXEfU_ (AudioKitManager.swift)
13 Lookwide                       0x10027033c globalinit_33_CB25F120035AD99142715FCFE02DB161_func105 (AudioKitManager.swift:176)
14 libdispatch.dylib              0x1ca2fd484 _dispatch_client_callout
15 libdispatch.dylib              0x1ca29f6c8 _dispatch_once_callout
16 libswiftCore.dylib             0x101e01e18 swift_once
17 Lookwide                       0x1002abef4 CreateAudioViewController.viewDidLoad() (AudioKitManager.swift:174)
18 Lookwide                       0x1002b1584 @objc CreateAudioViewController.viewDidLoad()
19 UIKitCore                      0x1f67e3fc8 -[UIViewController loadViewIfRequired]
20 UIKitCore                      0x1f67e43f8 -[UIViewController view]
21 UIKitCore                      0x1f675dcf0 -[UINavigationController preferredContentSize]
22 UIKitCore                      0x1f6712e6c -[UIPresentationController preferredContentSizeDidChangeForChildContentContainer:]
23 UIKitCore                      0x1f670ee90 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke
24 UIKitCore                      0x1f6db713c _runAfterCACommitDeferredBlocks
25 UIKitCore                      0x1f6da5138 _cleanUpAfterCAFlushAndRunDeferredBlocks
26 UIKitCore                      0x1f6dd4140 _afterCACommitHandler
27 CoreFoundation                 0x1ca8537cc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
28 CoreFoundation                 0x1ca84e460 __CFRunLoopDoObservers
29 CoreFoundation                 0x1ca84ea00 __CFRunLoopRun
30 CoreFoundation                 0x1ca84e1f0 CFRunLoopRunSpecific
31 GraphicsServices               0x1ccac7584 GSEventRunModal
32 UIKitCore                      0x1f6dab4c0 UIApplicationMain
33 Lookwide                       0x1000e11ec main (AppDelegate.swift:24)
34 libdyld.dylib                  0x1ca30dbb4 start

Adding my 2 cents, since this issue is bugging me also: it seems that it is related to a change in the mic hardware sample rate from 44.1K in older devices to 48K in new devices.
When I try to set
try AVAudioSession.sharedInstance().setPreferredSampleRate(48_000)
The result is a working microphone in newer devices, and a crashed one in older devices. When the rate is 44_100 it is reversed.
With the simulator there is no issue - regardless of the sample rate set by the Audio MIDI Setup, any session sample rate I set is respected, and working, on the simulator.

Interestingly, if both the session sample rate and the AK sample rate are set to the same value before the session is setActive, the reported sample rate will be what was set (in my case, 48K), but the actual analysis is performed according to the device's default (in my case, 44.1K). There is no crash.

For the time being I am querying in my code what's the actual device sample rate, and according to the result I have two datasets for analysis. I would very much like to be able to always set 48K.

For those looking for a workaround that seems to prevent the crash, this did it for me:

AKSettings.sampleRate = AudioKit.engine.inputNode.inputFormat(forBus: 0).sampleRate  

Place that line before you do anything microphone related, except declaring the mic constant.

EDIT: I edited the post based on some more experiments I did. My conclusion is that for the time being there is no way to override the default sample rate of the device's microphone, whereas it is possible with the simulator.

I have had this issue multiple times over the past few months for my app. I'm currently using 4.5.2 and have solved it mostly with the following:

  • Move AKMicrophone() to be the very first thing that's done. Before any AKSettings changes, before anything. For myself, it's in a singleton class that instantiates it at the start of my app after asking for Microphone permissions - before putting up the engine - anything.
  • To switch between .playback and .playAndRecord I use AKSettings.setSession and make sure to restart the engine when I switch to record mode. (This is for people who use recording only on one view and might not want the microphone up all the time - especially for the pass-through-audio on bluetooth headphones with a mic)
  • Implement listeners on AVAudio route changes and set the session to the appropriate state after headphones plugged in/out

You may also have to bring the engine back up after some route changes, depending on your setup. The biggest problem I have is with crackling audio when the app is started with bluetooth headphones plugged in, followed by unplugging them when the microphone is active. This is also because my headphones are 44.1K while the microphone on the iPhone 8 is 48K. That's a separate issue I believe from what was asked.

Hope this helps.

I've seen a spike of these crashes in my app.
Line 93, AKMicrophone.swift (called from init()).

iphone 6 running 12.1.2. latest Audiokit release.
This is affecting about 8% of my users now (~600+).

I managed to reproduce this issue(but I believe this is not the only way to cause this particular crash):

Steps to reproduce: init AKMicrophone while you're on a phone call.

The crash points to this line of the code in file AKMicrophone.swift

       let format = AVAudioFormat(commonFormat: AudioKit.engine.inputNode.inputFormat(forBus: 0).commonFormat,
                                  sampleRate: desiredFS,
                                  interleaved: AudioKit.engine.inputNode.inputFormat(forBus: 0).isInterleaved,
                                 channelLayout: AudioKit.engine.inputNode.inputFormat(forBus: 0).channelLayout!)

I am also facing this issue on 4.5.6 - I could not manage to reproduce it but I see crashes in ~5% of my users
[EDIT] What is interesting - 100% crashes happened on iOS 11, none on iOS 12

I'm looking into the solution proposed here: https://github.com/AudioKit/AudioKit/issues/1659 which might be relevant to this error as well. Basically, I think any route change should come with a reinitialization of the AKMicrophone because the sample rate is likely to have changed. Can you all try the 1659 solution and get back to me?

@aure uploading a version with this potential fix now -- I will let you all know results tomorrow

It looks like AKMicrophone.init() still crashes on iOS 11 devices at AKMicrophone.getFormatForDevice(), after implementing the solution proposed at #1659 . However, I haven't gathered enough data to confirm it is only on iOS 11.

Hoping this fixes it for everyone: https://github.com/AudioKit/AudioKit/pull/1664 we can reopen if necessary.

i have the same crash

Have the same crash with version 4.7

required condition is false: IsFormatSampleRateAndChannelCountValid(hwFormat)

This problem has been confused me for a while. i am now using AudioKit 4.7.1, but it also happened in some situation: AKMicrophone is init after AKSettings.setSession()
finally i got this problem solved is make sure AKMicrophone init is called before setSession().

I had two issues with the emulator. First one was a reported sampling rate of 41khz while the microphone was really running at 48Khz, leading to sound being altered. After trying to change the emulator/os settings just to get the reported and runing sampling rate match, I got this error back.
And yes I was effectively initializing the microphone first.

Using @ClassicalDude patch worked for me. Here is my code if it can helps somes:

  func startRecording() {
    // Set the AK sample rate to hardware supported sample rate
    AKSettings.sampleRate = AudioKit.engine.inputNode.inputFormat(forBus: 0).sampleRate

    // Set up a new AudioKit engine
    mic = AKMicrophone()
    AudioKit.output = AKBooster(mic, gain:0) // Mute microphone while connecting it

    // Get the sample rate from microphone if required for your processing
    let sampleRate = mic!.outputNode.outputFormat(forBus: 0).sampleRate
    print("Recorder: Recording at sampling rate", sampleRate)

    // Start recording
    do {try AudioKit.start()} catch {
      print("Recorder: can not start AudioKit")
      return
    }
  }

I am using AudioKit (~> 4.6).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adamjsutcliffe picture adamjsutcliffe  路  10Comments

vojtabohm picture vojtabohm  路  8Comments

trevor-sonic picture trevor-sonic  路  6Comments

minayko picture minayko  路  4Comments

mlostekk picture mlostekk  路  4Comments