Home > Mobile >  Using AVCapture session to capture audio frames
Using AVCapture session to capture audio frames

Time:07-19

I need to capture audio frames with a frequency of 48000, and Int16 bit frames. I need it in that format cause that is what my client expects. Right now the audio goes through but it sounds really funny. I'm using avcapture session with the following settings.

 let audioSettings = [AVFormatIDKey : kAudioFormatLinearPCM,
                    AVSampleRateKey : 48000,
             AVLinearPCMBitDepthKey : 16,
              AVLinearPCMIsFloatKey : false] as [String : Any]

I add those settings to AVCaptureDataOutput object

 private func setAudioDataOutput() -> EErrorCode {
    if dataOutput == nil {
        dataOutput = AVCaptureAudioDataOutput()
    }
    dataOutput!.setSampleBufferDelegate(self, queue: DispatchQueue(label: "myApp.AudioStreaming"))
    dataOutput!.audioSettings = audioSettings
    
    guard captureSession!.canAddOutput(dataOutput!) else {
        VsLogger.logError(logTag, "setAudioDataOutput() failed to add dataOutput for \(getName() ?? "no name found")")
        return .AudioOtherError
    }
    captureSession!.addOutput(dataOutput!)
    return .Success
}

and this is where I get the data from the CMSampleBuffer.

        guard let bufferData = self.getBlockDataBuffer(from: buffer) else { return }
    delegate.audioDataUpdate(bufferData, Int(sampleDescription.mSampleRate),
                             Int(sampleDescription.mChannelsPerFrame),
                             duration)

my getBlockDataBuffer func

   private func getBlockDataBuffer(from sampleBuffer: CMSampleBuffer) -> Data? {
           guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else { return nil }
           let dataLength = CMBlockBufferGetDataLength(blockBuffer)
           var blockBufferData  = [UInt8](repeating: 0, count: dataLength)
           let status = CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: dataLength,
                                            destination: &blockBufferData)
           guard status == noErr else {
            return nil
           }
           return Data(bytes: blockBufferData , count: dataLength)

when I print the AudioStreamBasicDescription I get the following.

sampleDescription.mChannelsPerFrame -> 2
sampleDescription.mSampleRate -> 48000
sampleDescription.mBytesPerFrame -> 2
sampleDescription.mFramesPerPacket -> 1
sampleDescription.mBytesPerPacket -> 2
duration -> 1

and here is what my cmSampleBuffer looks like:

    buffer numSamples: 557
    buffer duration seconds: 0.011604166666666667
    buffer isValid: true
    buffer totalSampleSize: 0
    buffer numSamples: 557
    buffer dataReadiness: ready
    sampleDescription: AudioStreamBasicDescription(mSampleRate: 48000.0, 
                                         mFormatID: 1819304813,
                                         mFormatFlags: 44,
                                         mBytesPerPacket: 2,
                                         mFramesPerPacket: 1,
                                         mBytesPerFrame: 2,
                                         mChannelsPerFrame: 2,
                                         mBitsPerChannel: 16,
                                         mReserved: 0)

so my settings are not persiting in my capture session?

CodePudding user response:

It turns out (as @RhythmicFistman suggested) I was just missing setting weather or not I wanted the frame to be interleaved. So my settings look like this now:

    let audioSettings = [AVFormatIDKey : kAudioFormatLinearPCM,
                   AVSampleRateKey : 48000,
            AVLinearPCMBitDepthKey : 16,
             AVLinearPCMIsFloatKey : false,
       AVLinearPCMIsNonInterleaved : false] as [String : Any]
  • Related