Swift AudioToolbox не воспроизводит аудиофайл и не заполняет аудиобуфер

Я пытаюсь воспроизвести аудиофайл с помощью AudioToolbox. Я написал это и быстро на основе старого примера C на веб-сайте Apple. Он компилируется и запускается, однако функция обратного вызова никогда не запускается после запуска CFRunLoop. (Он вызывается во время настройки, но я вызываю его вручную, чтобы это не учитывалось.)

Я понимаю, как это должно работать, когда эта строка называется:

status = AudioQueueNewOutput(&dataFormat, callback, &aqData, CFRunLoopGetCurrent(), commonModes, 0, &queue)

Предполагается создать объект AudioQueue, поместить его в CFRunLoop, установить функцию обратного вызова под названием "обратный вызов", а затем вернуть мне ссылку на объект очереди. Функция обратного вызова либо живет внутри AudioQueue, которая находится внутри CFRunLoop, либо функция обратного вызова живет непосредственно в CFRunLoop. Точно сказать не могу.

Когда я закончу настройку, я вызываю: status = AudioQueueStart(aqData.mQueue!, nil), который "запускает" очередь.

Тогда я звоню:

  repeat {
       CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 0.1, false)
  }

Насколько я понимаю, это должно вызвать аудио-очередь, которая, в свою очередь, вызывает мою функцию обратного вызова. Однако с этого момента функция обратного вызова никогда не получает удар. Я и подумал, что может быть способ проверить аудио-очередь или, возможно, проверить CFRunLoop. Возможно, я где-то ошибся в одном из указателей.

В результате приложение проигрывает только тишину.

    let kNumberBuffers = 3;
    var aqData = AQPlayerState()
    var bufferLength : Float64 = 0.1
 func playAudioFileWithToolbox(){
        let bundle = Bundle.main
        let permissions : AudioFilePermissions = .readPermission
        let filePath = bundle.path(forResource: "dreams", ofType: "wav")!
        var filePathArray = Array(filePath.utf8)
        let filePathSize = filePath.count
        let audioFileUrl = CFURLCreateFromFileSystemRepresentation(nil, &filePathArray, filePathSize, false)
        var  status = AudioFileOpenURL(audioFileUrl!, permissions, kAudioFileWAVEType, &aqData.mAudioFile)
        if status != noErr{
            print("ErrorOpeningAudioFileUrl")
        }
        var dataFormatSize:UInt32 = UInt32(MemoryLayout<AudioStreamBasicDescription>.size)
        status = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyDataFormat, &dataFormatSize, &aqData.mDataFormat)
        if status != noErr{
            print("Error getting AudioStreamBasicDescription")
        }
        var queue : AudioQueueRef? = aqData.mQueue
        var dataFormat = aqData.mDataFormat
        let commonModes = CFRunLoopMode.commonModes.rawValue
        status = AudioQueueNewOutput(&dataFormat, callback, &aqData, CFRunLoopGetCurrent(), commonModes, 0, &queue)
        if status == noErr{
            aqData.mQueue = queue
        } else {
            print("TroubleSettingUpOutputQueue")
        }
        var maxPacketSize:UInt32 = 0;
        var propertySize:UInt32 = UInt32(MemoryLayout.size(ofValue: maxPacketSize))
        AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyPacketSizeUpperBound, &propertySize, &maxPacketSize)
        var bufferByteSize = aqData.bufferByteSize
        DeriveBufferSize(ASBDesc: &dataFormat, maxPacketSize: maxPacketSize, seconds: bufferLength, outBufferSize: &bufferByteSize, outNumPacketsToRead: &aqData.mNumPacketsToRead)
        aqData.bufferByteSize = bufferByteSize
        let isFormatVBR = aqData.mDataFormat.mBytesPerPacket == 0 || aqData.mDataFormat.mFramesPerPacket == 0
        if isFormatVBR{
            aqData.mPacketDescs = UnsafeMutablePointer<AudioStreamPacketDescription>.allocate(capacity: Int(aqData.mNumPacketsToRead))
        }  else {
            aqData.mPacketDescs = nil
        }
        var cookieSize = UInt32(MemoryLayout.size(ofValue: UInt32.self))
        let couldNotGetProperty = AudioFileGetPropertyInfo(aqData.mAudioFile!, kAudioFilePropertyMagicCookieData, &cookieSize, nil)

        if couldNotGetProperty == 0 && cookieSize > 0{

            var magicCookie = UnsafeMutableRawPointer.allocate(byteCount: Int(cookieSize), alignment: MemoryLayout<UInt32>.alignment)
            status = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyMagicCookieData, &cookieSize, &magicCookie)
            if status != noErr{
                print("Error:Failed to get magic cookie.")
            }

            AudioQueueSetProperty(aqData.mQueue!, kAudioQueueProperty_MagicCookie, magicCookie, cookieSize)
            magicCookie.deallocate()
        }
        aqData.mCurrentPacket = 0
        for i in 0..<kNumberBuffers{
            var pointer = aqData.mBuffers?.advanced(by: i)
            status = AudioQueueAllocateBuffer(aqData.mQueue!, aqData.bufferByteSize, &pointer)
            if status != noErr{
                print("Error allocating audio buffer.")
                continue
            }
            var buffer = aqData.mBuffers![i]
            callback(&aqData, aqData.mQueue!, &buffer) //I can imagine how this does anything when it is not running
        }
        //Set Volume
        AudioQueueSetParameter(aqData.mQueue!, kAudioQueueParam_Volume, 0.5)//I have way bigger problems

        //Start Playing
        aqData.mIsRunning = true
        status = AudioQueueStart(aqData.mQueue!, nil)
        if status != noErr{
            print("Error:Failed to start audio queue.")
        }
        repeat {
            CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 0.1, false)
        } while aqData.mIsRunning
        CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 1, false)
    }
    private let callback: AudioQueueOutputCallback = { userData, inAQ, inBuffer in
        var aqData = userData!.load(as: AQPlayerState.self)       // 255
        if !aqData.mIsRunning{ return }                     // 2
        var numBytesReadFromFile : UInt32 = 0
        var numPackets = aqData.mNumPacketsToRead
        AudioFileReadPacketData(aqData.mAudioFile!, false, &numBytesReadFromFile, aqData.mPacketDescs, aqData.mCurrentPacket, &numPackets, inBuffer)
        if (numPackets > 0) {
            inBuffer.pointee.mAudioDataByteSize = numBytesReadFromFile
            let packetCount = aqData.mPacketDescs!.pointee.mVariableFramesInPacket
            AudioQueueEnqueueBuffer (
                aqData.mQueue!,
                inBuffer,
                packetCount,
                aqData.mPacketDescs
            );
            aqData.mCurrentPacket += Int64(numPackets)
        } else {
            AudioQueueStop (aqData.mQueue!,false)
            aqData.mIsRunning = false
        }
    }

    func DeriveBufferSize (ASBDesc: inout AudioStreamBasicDescription, maxPacketSize:UInt32, seconds:Float64, outBufferSize: inout UInt32,outNumPacketsToRead: inout UInt32) {
        let maxBufferSize = 0x50000
        let minBufferSize = 0x4000
        if ASBDesc.mFramesPerPacket != 0 {
            let numPacketsForTime = ASBDesc.mSampleRate / Float64(ASBDesc.mFramesPerPacket) * seconds
            outBufferSize = UInt32(numPacketsForTime) * maxPacketSize
        } else {                                                         // 9
            outBufferSize = max(UInt32(maxBufferSize), maxPacketSize)
        }

        if outBufferSize > maxBufferSize && outBufferSize > maxPacketSize{  //10
            outBufferSize = UInt32(maxBufferSize)
        } else if outBufferSize < minBufferSize {
            outBufferSize = UInt32(minBufferSize)
        }
        outNumPacketsToRead = outBufferSize / UInt32(maxPacketSize)           // 12
    }
}

struct AQPlayerState{
    var mDataFormat:AudioStreamBasicDescription = AudioStreamBasicDescription()
    var mQueue:AudioQueueRef?
    var mBuffers:AudioQueueBufferRef? = UnsafeMutablePointer<AudioQueueBuffer>.allocate(capacity: 3)
    var mAudioFile: AudioFileID?
    var bufferByteSize:UInt32 = 0
    var mCurrentPacket:Int64 = 0
    var mNumPacketsToRead:UInt32 = 0
    var mPacketDescs : UnsafeMutablePointer<AudioStreamPacketDescription>?
    var mIsRunning : Bool = false
    init(){

    }
}

0 ответов

Другие вопросы по тегам