(swift) 当 AudioStreamPacketDescription 为 nil 时调试 CrashIfClientProvidedBogusAudioBufferList 的方法?

(swift) ways to debug CrashIfClientProvidedBogusAudioBufferList when the AudioStreamPacketDescription is nil?

我在尝试一次时遇到 CrashIfClientProvidedBogusAudioBufferList 异常 AudioConverterFillComplexBuffer 回调 returns。抛出此异常的可能原因是什么?

供参考,这是我的电话

AudioConverterFillComplexBuffer(audioConverterRef,  
fillComplexCallback,  
&convertInfo,  
&framesToDecode,  
&localPcmBufferList,  

&回调:

func fillComplexxCallback(myConverter: AudioConverterRef, packetNumber: UnsafeMutablePointer<UInt32>,   
ioData: UnsafeMutablePointer<AudioBufferList>, aspd: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>>,  
userInfo: UnsafeMutablePointer<Void>) -> OSStatus {  

    var convertInfo = UnsafeMutablePointer<AudioConvertInfo>(userInfo).memory  

    if (packetNumber.memory > (convertInfo.audioBuffer.mDataByteSize / convertInfo.numberOfPackets)) {  
        packetNumber.memory = (convertInfo.audioBuffer.mDataByteSize / convertInfo.numberOfPackets)  
    }  

    ioData.memory.mNumberBuffers = 1  
    var buffer = AudioBuffer(mNumberChannels: 2, mDataByteSize: convertInfo.audioBuffer.mDataByteSize, mData: ioData.memory.mBuffers.mData)  
    ioData.memory.mBuffers = buffer  

     /* if the following is uncommented out, a exception is thrown */
    // aspd.memory = convertInfo.packetDescriptions 
    packetNumber.memory = convertInfo.numberOfPackets  
    convertInfo.done = true  

        return 0  
}  

这里是 AudioConvertInfo's 结构:

struct AudioConvertInfo {
    var done: Bool! //conversion of audio is finished
    var numberOfPackets: UInt32!
    var audioBuffer: AudioBuffer!
    var audioPlayer: CCPlayer!
    var packetDescriptions: AudioStreamPacketDescription!

    init(done: Bool?, numberOfPackets: UInt32?, audioBuffer: AudioBuffer?, packetDescriptions: AudioStreamPacketDescription!, audioPlayer: CCPlayer!) {
        self.done = done
        self.numberOfPackets = numberOfPackets
        self.audioBuffer = audioBuffer
        self.packetDescriptions = packetDescriptions
        self.audioPlayer = audioPlayer
    }
}

我似乎找不到任何可靠的文档。我注意到 aspd (AudioStreamPacketDescription) 正在返回 nil。这对于确定音频数据缓冲区中数据包大小不同或音频数据包之间存在非音频数据的数据包很重要。此代码将在 aspd.memory = convertInfo.packetDescriptions 上抛出异常,但如果代码被注释掉 - 将抛出 CrashIfClientProvidedBogusAudioBufferList。我的理论是,如果我弄清楚为什么 AudioStreamPacketDescription 为 nil

,则此回调将正常工作

看起来 AudioStreamPacketDescription is nil 不是问题。
根据 Apple 文档可以是 nil,基本上取决于音频格式:
AudioConverterComplexInputDataProc

outDataPacketDescription: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>> - If not NULL on input, the audio converter expects this callback to provide an array of AudioStreamPacketDescription structures on output, one for each packet of audio data you are providing in the ioData parameter.

AudioConverterFillComplexBuffer

outPacketDescription: UnsafeMutablePointer<AudioStreamPacketDescription> - On input, must point to a block of memory capable of holding the number of packet descriptions specified in the ioOutputDataPacketSize parameter. (See Audio Format Services Reference for functions that let you determine whether an audio format uses packet descriptions). If not NULL on output and if the audio converter’s output format uses packet descriptions, then this parameter contains an array of packet descriptions.

真正的问题放在AudioConvertInfo结构这一行:

var packetDescriptions: AudioStreamPacketDescription!  

结构只保留单个 AudioStreamPacketDescription 结构。
然后在 fillComplexCallback 函数中使用它:

outDataPacketDescription.memory.memory = convertInfo.packetDescriptions

因此您试图将单个 AudioStreamPacketDescription 结构设置为参数 outDataPacketDescription,该参数需要 AudioStreamPacketDescription 结构数组(不仅仅是单个实例)。

这个问题可以通过保留和使用 AudioStreamPacketDescription 结构数组来解决。
AudioConvertInfo 结构的更新版本:

struct AudioConvertInfo {
    var done: Bool!
    var numberOfPackets: UInt32!
    var audioBuffer: AudioBuffer!
    var audioPlayer: CCPlayer!
    var packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>!

    init(done: Bool?, numberOfPackets: UInt32?, audioBuffer: AudioBuffer?, packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>!, audioPlayer: CCPlayer!) {
        self.done = done
        self.numberOfPackets = numberOfPackets
        self.audioBuffer = audioBuffer
        self.packetDescriptions = packetDescriptions
        self.audioPlayer = audioPlayer
    }
}

// Usage:
convertInfo = AudioConvertInfo(done: false, numberOfPackets: numberPackets, audioBuffer: AudioBuffer(mNumberChannels: 2, mDataByteSize: numberBytes, mData: &iData), packetDescriptions: packetDescriptions, audioPlayer: self)

fillComplexCallback 函数的更新版本:

func fillComplexCallback(inAudioConverter: AudioConverterRef, ioNumberDataPackets: UnsafeMutablePointer<UInt32>, ioData: UnsafeMutablePointer<AudioBufferList>, outDataPacketDescription: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>>, inUserData: UnsafeMutablePointer<Void>) -> OSStatus {
    var convertInfo = UnsafeMutablePointer<AudioConvertInfo>(inUserData).memory

    if convertInfo.done == true {
        ioNumberDataPackets.memory = 0
        return 100
    }
    ioData.memory.mNumberBuffers = 1
    let buffer = convertInfo.audioBuffer
    ioData.memory.mBuffers = buffer

    if outDataPacketDescription != nil {
        outDataPacketDescription.memory = convertInfo.packetDescriptions
    }

    ioNumberDataPackets.memory = convertInfo.numberOfPackets
    convertInfo.done = true

    return 0
}

// Usage:  
status = AudioConverterFillComplexBuffer(audioConverterRef, fillComplexCallback, &convertInfo!, &framesToDecode, &localPcmBufferList!, nil)

希望它能解决您的问题。