Search code examples
swiftaudiobufferavaudioplayer

Swift - How to get the current volume from the microphone input (AVAudioPCMBuffer)


I am recording audio from the microphone and streaming that audio to another device. Currently, this audio is sent across the stream even when the user isn't talking. But I've noticed that a lot of streaming services don't actually send your mic input when they detect that there is very little noise coming from it.

So I'm asking, how do I see how loud the input is before streaming it to the other device.

I'm recording audio using a AVAudioPlayerNode attached to an AVAudioEngine. I then use the following to actually record:

localInput?.installTap(onBus: 0, bufferSize: 4096, format: localInputFormat) {
    (buffer, when) -> Void in

Here, buffer is an AVAudioPCMBuffer, so I need to be able to see the volume from this buffer.

Thanks!


Solution

  • I was able to get this done using the following code:

                let arraySize = Int(buffer.frameLength)
                var channelSamples: [[DSPComplex]] = []
                let channelCount = Int(buffer.format.channelCount)
    
                for i in 0..<channelCount {
    
                    channelSamples.append([])
                    let firstSample = buffer.format.isInterleaved ? i : i*arraySize
    
                    for j in stride(from: firstSample, to: arraySize, by: buffer.stride*2) {
    
                        let channels = UnsafeBufferPointer(start: buffer.floatChannelData, count: Int(buffer.format.channelCount))
                        let floats = UnsafeBufferPointer(start: channels[0], count: Int(buffer.frameLength))
                        channelSamples[i].append(DSPComplex(real: floats[j], imag: floats[j+buffer.stride]))
    
                    }
                }
    
                var spectrum = [Float]()
    
                for i in 0..<arraySize/2 {
    
                    let imag = channelSamples[0][i].imag
                    let real = channelSamples[0][i].real
                    let magnitude = sqrt(pow(real,2)+pow(imag,2))
    
                    spectrum.append(magnitude)
                }
    

    Credit for this answer goes to this question.