Search code examples
swiftswift3avaudiorecorder

Swift 3 live microphone levels capture


I'm trying to capture the levels coming in from the phones microphone. I am setting up a app so a user can create voice memos. I have the code setup to record the memos and save them on the phone I am now trying to set up a sound wave to animate the view when the user is typing.

I have started using the library SwiftSiriWaveformView which is working very well. Now I just need to figure out how to capture the microphone level.

I have created a method

internal func refreshAudioView(_:Timer) {
    if self.recorder == nil {
        self.endTimer()

        return
    }

    print("Average Power: \(CGFloat(self.recorder.averagePower(forChannel: 0)))")
}

Which is added to a timer in this method

@IBAction func startRecordingPressed(_ sender: UIButton) {
    if self.recorder != nil {
        //if here it means that the record button was double clicked
        return
    }
    self.filename = "wnw-voice-memo\(getDateFormatter("dd-MM-y_hmmss").string(from: Date())).m4a"
    self.url = getDocumentsDirectory().appendingPathComponent(self.filename)
    print(self.url)

    let settings = [
        AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
        AVSampleRateKey: 12000,
        AVNumberOfChannelsKey: 1,
        AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
    ]

    do {
        self.recorder = try AVAudioRecorder(url: self.url, settings: settings)
        self.recorder.delegate = self
        self.recorder.record()

        timer = Timer.scheduledTimer(timeInterval: 0.009, target: self, selector: #selector(refreshAudioView(_:)), userInfo: nil, repeats: true)
    } catch {
        //failed to record!
    }
}

However when I run the app the average power is only ever shows as Average Power: -160.0

I have tried researching this but I have only found other solutions related to generating an audio wave from a save file, not from a live stream.

Does anyone know how I can get the current microphone levels?


Solution

  • Set recorder.meteringEnabled = true and in refreshAudioView call recorder. updateMeters() before accessing peakPowerForChannel & averagePowerForChannel. Also try to read power of channel 1 in addition to channel 0 you already monitoring.