3

I'm attempting to create a continuous FIFO audio recorder in Swift. I'm running into and issue while trying to create the audioQueueCallback.

From the docs AudioTimeStamp has this init method:

AudioTimeStamp(mSampleTime: Float64, mHostTime: UInt64, mRateScalar: Float64, mWordClockTime: UInt64, mSMPTETime: SMPTETime, mFlags: AudioTimeStampFlags, mReserved: UInt32)

And I have not idea how to use it.

It seems to me like the device should have a reliable internal clock to be able to manage audioQueues off of but I haven't been able to find any documentation for it.

Here's my attempt at creating a BufferQueue:

ypealias WYNDRInputQueueCallback = ((Data) -> Void)

class WYNDRInputQueue {

  class WYNDRInputQueueUserData {
    let callback: WYNDRInputQueueCallback
    let bufferStub: NSData

    init(callback: @escaping WYNDRInputQueueCallback, bufferStub: NSData){
      self.callback = callback
      self.bufferStub = bufferStub
    }
  }


  private var audioQueueRef: AudioQueueRef?
  private let userData: WYNDRInputQueueUserData



  public init(asbd: inout AudioStreamBasicDescription, callback: @escaping WYNDRInputQueueCallback, buffersCount: UInt32 = 3, bufferSize: UInt32 = 9600) throws {

    self.userData = WYNDRInputQueueUserData(callback: callback, bufferStub: NSMutableData(length: Int(bufferSize))!)

    let userDataUnsafe = UnsafeMutableRawPointer(Unmanaged.passRetained(self.userData).toOpaque())

    let input = AudioQueueNewInput(&asbd,
                                   audioQueueInputCallback,
                                   userDataUnsafe,
                                   .none,
                                   .none,
                                   0,
                                   &audioQueueRef)

    if input != noErr {
      throw InputQueueError.genericError(input)
    }

    assert(audioQueueRef != nil )

    for _ in 0..<buffersCount {
      var bufferRef: AudioQueueBufferRef?

      let bufferInput = AudioQueueAllocateBuffer(audioQueueRef!, bufferSize, &bufferRef)

      if bufferInput != noErr {
        throw InputQueueError.genericError(bufferInput)
      }

      assert(bufferRef != nil)

Here's where I'm using the audioTimeStamp:

      audioQueueInputCallback(userDataUnsafe, audioQueueRef!, bufferRef!, <#T##UnsafePointer<AudioTimeStamp>#>, 0, nil)
    }
  }

  private let audioQueueInputCallback: AudioQueueInputCallback = { (inUserData, inAQ, inBuffer, inStartTime, inNumberPacketDescriptions, inPacketDescs) in

    let userData = Unmanaged<WYNDRInputQueueUserData>.fromOpaque(inUserData!).takeUnretainedValue()

    let dataSize = Int(inBuffer.pointee.mAudioDataByteSize)

    let inputData = Data(bytes: inBuffer.pointee.mAudioData, count: dataSize)

    userData.callback(inputData)

    AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil)
  }

Any advice here would be greatly appreciated!

aBikis
  • 323
  • 4
  • 16

1 Answers1

1

I'm not sure how the timestamp is going to be used or who is going to use it, but if in doubt, why not use the number of samples you've recorded as the timestamp?

var timestamp = AudioTimeStamp()

timestamp.mSampleTime = numberOfSamplesRecorded
timestamp.mFlags = .sampleHostTimeValid
Rhythmic Fistman
  • 34,352
  • 5
  • 87
  • 159
  • Thanks. I guess I just didn't understand how the class worked or if all it's variables are necessary. I've commented in my code where I call the use the time stamp. I – aBikis May 17 '17 at 17:56
  • 1
    Yeah, it's a messy attempt at a union. It would make a lot more sense as a swift enumeration. – Rhythmic Fistman May 18 '17 at 00:05