Can not set input to built in mic when wired headphones connected

245 views
Skip to first unread message

Richie Melpignano

unread,
Jul 15, 2017, 2:13:11 PM7/15/17
to AudioKit Users Group
Hey Aure,

When I am trying to set the input device to the Front microphone but I have headphones plugged in, AudioKit attempts to have the input come from the headphones itself. When the headphones are not attached, the input appears to be coming from the Front microphone, though. This is strange because I am setting the microphone device to a connected device with a deviceID containing "Front", so I would think it would always be set to the Front microphone.

On a similar note, i have replaced the property AudioKit.inputDevices with a function setAKInputDevices() and the function AKMicrophone.setInput(input:) with a function setAKMicrophoneDevice(input:) because I was experiencing crashes whenever headphones were connected. I believe this was due to the fact that each of these methods contained the line "if device.dataSources!.isEmpty", which I replaced with "if device.dataSources == nil", since this method is checking an AVAudioSessionPortDescription not an AKDevice. Please let me know if I am using these functions incorrectly. Here are those functions below, followed by my code where I am trying to always set the input device to the front microphone, which lives within the viewDidLoad(). The configureNodes function just sets up the player, waveforms, etc. :

 func setAKInputDevices() -> [AKDevice]? {

        

        

        var returnDevices = [AKDevice]()

        if let devices = session.availableInputs {

            for device in devices {

                

                if device.dataSources == nil {

                    returnDevices.append(AKDevice(name: device.portName, deviceID: device.uid))

                } else {

                    for dataSource in device.dataSources! {

                        returnDevices.append(AKDevice(name: device.portName,

                                                      deviceID: "\(device.uid) \(dataSource.dataSourceName)"))

                    }

                }

            }

            return returnDevices

        }

        return nil

        

    }

    

    func setAKMicrophoneDevice(input: AKDevice) throws {

        if let devices = AVAudioSession.sharedInstance().availableInputs {

            for device in devices {

                if device.dataSources == nil {

                    if device.uid == input.deviceID {

                        do {

                            try AVAudioSession.sharedInstance().setPreferredInput(device)

                        } catch {

                            AKLog("Could not set the preferred input to \(input)")

                        }

                    }

                } else {

                    for dataSource in device.dataSources! {

                        if input.deviceID == "\(device.uid) \(dataSource.dataSourceName)" {

                            do {

                                try AVAudioSession.sharedInstance().setInputDataSource(dataSource)

                            } catch {

                                AKLog("Could not set the preferred input to \(input)")

                            }

                        }

                    }

                }

            }

        }

    }



BELOW LIVES IN VIEWDIDLOAD()....


do {

            try AKSettings.setSession(category: .playAndRecord, with: [.mixWithOthers, .defaultToSpeaker, .allowBluetoothA2DP])

            AKSettings.bufferLength = .medium

            

            

            session.requestRecordPermission({ (allowed) in

                if allowed {

                    print("allowed recording")

 

                    let inputDevices = self.setAKInputDevices()

                    print(inputDevices)

                    

                    //TODO: figure out how to set input device to Front mic when headphones are attached.

                    

                    if let inputs = inputDevices {

                        do {

                            self.microphone = AKMicrophone()

                            

                            for input in inputs {

                                if input.deviceID.contains("Front") {

                                    try self.setAKMicrophoneDevice(input: input)

                                }

                            }

                            

                            self.micCopy = AKBooster(self.microphone)

                            self.micCopy.gain = 2.0

                            

                            self.recordingNode = AKMixer([self.micCopy])

                            

                            self.configureNodes()

                            

                        } catch let error {

                            print("could not access input devices: \(error.localizedDescription)")

                        }

                        

                    } else {

                        print("no input devices found")

                    }

                    

                } else {

                    print("recording not allowed")

                }

            })

        } catch let error {

            print("recording session error: \(error.localizedDescription)")

        }


END OF VIEWDIDLOAD()....


 func configureNodes() {

        

        do {

            let file = try AKAudioFile(forReading: beatURL)

            player = try AKAudioPlayer(file: file, looping: true, completionHandler: nil)

            passthroughPlayer = AKMixer(player)

            

            recordingNode.connect(player)

            

        } catch let error {

            fatalError("Could not read beat URL at \(beatURL): \(error.localizedDescription)")

        }

        

        

        if let player = player {

            

            let waveformWindowSize = CGSize(width: self.view.frame.width, height: self.view.frame.height / 6)

            

            print(beatPlotView.frame)

            beatPlot = AKNodeOutputPlot(player, frame: CGRect(origin: beatPlotView.frame.origin, size: waveformWindowSize))

            beatPlot.plotType = .buffer

            beatPlot.shouldFill = true

            beatPlot.backgroundColor = .clear

            beatPlot.shouldMirror = true

            beatPlot.color = .yellow

            

            

            recordedAudioPlot = AKNodeOutputPlot(passthroughPlayer, frame: CGRect(origin: recordedAudioPlotView.frame.origin, size: waveformWindowSize))

            recordedAudioPlot.plotType = .rolling

            recordedAudioPlot.shouldFill = true

            recordedAudioPlot.backgroundColor = .clear

            recordedAudioPlot.shouldMirror = true

            recordedAudioPlot.color = .red

            

            if let micCopy = micCopy {

                

                

                let micPlot = AKNodeOutputPlot(micCopy, frame: CGRect(origin: beatBufferView.frame.origin, size: waveformWindowSize))

                micPlot.plotType = .buffer

                micPlot.shouldFill = true

                micPlot.backgroundColor = .clear

                micPlot.shouldMirror = true

                micPlot.color = .blue

                

                self.view.addSubview(micPlot)

            }

            

            self.view.addSubview(recordedAudioPlot)

            self.view.addSubview(beatPlot)

            

        }

        

        

        print(AudioKit.outputDevices)

        AudioKit.output = passthroughPlayer

        AudioKit.start()

        player.play()

        

    }


Richie Melpignano

unread,
Jul 18, 2017, 2:29:28 AM7/18/17
to AudioKit Users Group
Any ideas, anyone? I added Even with the AVAudioSession.sharedInstance().preferredInput printing <AVAudioSessionPortDescription: 0x17001ba40, type = MicrophoneBuiltIn; name = iPhone Microphone; UID = Built-In Microphone; selectedDataSource = Front>  before starting the AudioKit, the device still tries to read microphone input from the connected headphones. When the headphones are not connected, AudioKit is able to read input from the Front microphone, as intended. I have been trying tons of things and still can't get anything to work. Please help!!!

Rolf Hanson

unread,
Jul 19, 2017, 4:19:55 PM7/19/17
to AudioKit Users Group
create this extension on AVAudioSession

then call selectBottomDeviceMic() after you do AudioKit.start(), like this:

AVAudioSession.sharedInstance().selectBottomDeviceMic()



extension AVAudioSession {

    func selectBottomDeviceMic() {

        guard let inputs = self.availableInputs else {

            return

        }

        var builtInMicPort: AVAudioSessionPortDescription?

        for port in inputs {

            if port.portType == AVAudioSessionPortBuiltInMic {

                builtInMicPort = port

                for source in port.dataSources! {

                    if source.orientation == AVAudioSessionOrientationBottom {

                        do {

                            try builtInMicPort!.setPreferredDataSource(source)

                        } catch {

                            print("setPreferredDataSource ERROR")

                        }

                        do {

                            try self.setPreferredInput(builtInMicPort)

                        } catch {

                            print("setPreferredInput ERROR")

Ryan McLeod

unread,
Jul 19, 2017, 4:20:03 PM7/19/17
to AudioKit Users Group
Hey Richie, this sounds somewhat familiar to something I experienced. For me, single microphone devices were crashing because the `EZAudioDevice`s returned by `EZAudioDevice.inputDevices()` sometimes had a nil `dataSource` attribute. You aren't by change setting the `AVAudioSession` mode to `.measurement` are you? Is the device you want simply not in the list of returned devices or will it not switch to it?

Rolf Hanson

unread,
Jul 19, 2017, 4:20:09 PM7/19/17
to AudioKit Users Group
add this extension on AVAudioSession then call selectBottomDevice() after AudioKit.start()

Richie Melpignano

unread,
Jul 20, 2017, 12:18:21 PM7/20/17
to AudioKit Users Group
The device exists in availableInputs in the session. If I set the preferredInput before setting the preferredDataSource, I am able to see that the preferredInput is my desired input later on in viewDidLoad() right before AudioKit starts (through print functions). But still, even with the preferredInput being a built-in mic, when the headphones are connected it still takes input from the headphones microphone. But yes, to fix the crashing issue when a headphone is attached, I did not use AudioKit's setInputDevice function, but created my own, (setAKMicrophoneDevice) and replaced "if device.dataSources!.isEmpty" with "if device.dataSources == nil"

Ryan McLeod

unread,
Jul 21, 2017, 12:54:57 AM7/21/17
to AudioKit Users Group
Is there a difference in behavior between starting the app with headphones connected and connecting them after start?

Richie Melpignano

unread,
Jul 25, 2017, 11:15:23 PM7/25/17
to AudioKit Users Group
No difference for me after I had patched the headphone datasource.isEmpty issue.
Reply all
Reply to author
Forward
0 new messages