A way to crop AudioFile while recording?

Viewed 425

I'm writing a first in first out recording app that buffers up to 2.5 mins of audio using AudioQueue. I've got most of it figured out but I'm at a roadblock trying to crop audio data.

I've seen people do it with AVAssetExportSession but it seems like it wouldn't be performant to export a new track every time the AudioQueueInputCallback is called.

I'm not married to using AVAssestExportSession by any means if anyone has a better idea.

Here's where I'm doing my write and was hoping to execute the crop.

 var beforeSeconds = TimeInterval() // find the current estimated duration (not reliable)
    var propertySize = UInt32(MemoryLayout.size(ofValue: beforeSeconds))
    var osStatus = AudioFileGetProperty(audioRecorder.recordFile!, kAudioFilePropertyEstimatedDuration, &propertySize, &beforeSeconds)

    if numPackets > 0 {
      AudioFileWritePackets(audioRecorder.recordFile!, // write to disk
                                       false,
                                       buffer.mAudioDataByteSize,
                                       packetDescriptions,
                                       audioRecorder.recordPacket,
                                       &numPackets,
                                       buffer.mAudioData)
      audioRecorder.recordPacket += Int64(numPackets) // up the packet index

      var afterSeconds = TimeInterval() // find the after write estimated duration (not reliable)
      var propertySize = UInt32(MemoryLayout.size(ofValue: afterSeconds))
      var osStatus = AudioFileGetProperty(audioRecorder.recordFile!, kAudioFilePropertyEstimatedDuration, &propertySize, &afterSeconds)
      assert(osStatus == noErr, "couldn't get record time")

      if afterSeconds >= 150.0 {
        print("hit max buffer!")
        audioRecorder.onBufferMax?(afterSeconds - beforeSeconds)
      }
    }

Here's where the callback is executed

func onBufferMax(_ difference: Double){
    let asset = AVAsset(url: tempFilePath)
    let duration = CMTimeGetSeconds(asset.duration)
    guard duration >= 150.0 else { return }

    guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
      print("exporter init failed")
      return }


    exporter.outputURL = getDocumentsDirectory().appendingPathComponent("buffered.caf") // helper function that calls the FileManager
    exporter.outputFileType = AVFileTypeAppleM4A

    let startTime = CMTimeMake(Int64(difference), 1)
    let endTime = CMTimeMake(Int64(WYNDRConstants.maxTimeInterval + difference), 1)

    exporter.timeRange = CMTimeRangeFromTimeToTime(startTime, endTime)
    exporter.exportAsynchronously(completionHandler: {
      switch exporter.status {
      case .failed:
        print("failed to export")
      case .cancelled:
        print("canceled export")
      default:
        print("export successful")
      }
    })
  }
1 Answers
Related