Search code examples
iosswiftavcapturesessionaudiobuffer

Capturing volume levels with AVCaptureAudioDataOutputSampleBufferDelegate in swift


I'm trying to live volume levels using AVCaptureDevice etc it compiles and runs but the values just seem to be random and I keep getting overflow errors as well.

EDIT:

also is it normal for the RMS range to be 0 to about 20000?

        if let audioCaptureDevice : AVCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeAudio){



            try audioCaptureDevice.lockForConfiguration()

            let audioInput = try AVCaptureDeviceInput(device: audioCaptureDevice)
            audioCaptureDevice.unlockForConfiguration()

            if(captureSession.canAddInput(audioInput)){
                captureSession.addInput(audioInput)
                print("added input")
            }


            let audioOutput = AVCaptureAudioDataOutput()

            audioOutput.setSampleBufferDelegate(self, queue: GlobalUserInitiatedQueue)

            if(captureSession.canAddOutput(audioOutput)){
                captureSession.addOutput(audioOutput)
                print("added output")
            }


            //supposed to start session not on UI queue coz it takes a while
            dispatch_async(GlobalUserInitiatedQueue) {
                print("starting captureSession")
                self.captureSession.startRunning()
            }
        }

...

func captureOutput(captureOutput: AVCaptureOutput!, let didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {

    // Needs to be initialized somehow, even if we take only the address
    var audioBufferList = AudioBufferList(mNumberBuffers: 1,
        mBuffers: AudioBuffer(mNumberChannels: 1, mDataByteSize: 0, mData: nil))
    //this needs to be in method otherwise only runs 125 times?
    var blockBuffer: CMBlockBuffer?

    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
        sampleBuffer,
        nil,
        &audioBufferList,
        sizeof(audioBufferList.dynamicType),
        nil,
        nil,
        UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment),
        &buffer
    )



    let abl = UnsafeMutableAudioBufferListPointer(&audioBufferList)

    for buffer in abl{
        let samples = UnsafeMutableBufferPointer<Int16>(start: UnsafeMutablePointer(buffer.mData),
            count: Int(buffer.mDataByteSize)/sizeof(Int16))


        var sum:Int = 0
        for sample in samples {
            sum = sum + Int(sample*sample)

        }

        let rms = sqrt(Double(sum)/count)
    }

Solution

  • It appears I have it working. I casted sample to an Int64 before doing any manipulations.

            for buffer in abl{
            let samples = UnsafeMutableBufferPointer<Int16>(start: UnsafeMutablePointer(buffer.mData),
                count: Int(buffer.mDataByteSize)/sizeof(Int16))
    
            var sum:Int64 = 0
    
            for sample in samples {
             let s = Int64(sample)
             sum +=s*s
            }
    
    
            dispatch_async(dispatch_get_main_queue()) {
    
                self.volLevel.text = String(sqrt(Float(sum/Int64(samples.count))))
            }