Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

i'm getting a CrashIfClientProvidedBogusAudioBufferList exception when attempting once my AudioConverterFillComplexBuffer callback returns. What are the possibile reasons why this exception would be thrown?

for reference, here is my call

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

& the callback:

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  
}  

here's AudioConvertInfo's struct:

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
    }
}

I can't seem to find any solid documentation around. I've noticed was the aspd (AudioStreamPacketDescription) is returning nil. This is important to determine one packet in a buffer of audio data where the sizes of the packets differ or where there is non-audio data between audio packets. This code will throw an exception on aspd.memory = convertInfo.packetDescriptions , but if the code is commented out - the CrashIfClientProvidedBogusAudioBufferList is thrown. My theory is that this callback will work fine if i figure out why the AudioStreamPacketDescription is nil

like image 715
3254523 Avatar asked Oct 19 '22 06:10

3254523


1 Answers

Looks like AudioStreamPacketDescription is nil is not a problem.
According to Apple documentation it can be nil, basically it depends on audio format:
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.

The real problem is placed in AudioConvertInfo structure in this line:

var packetDescriptions: AudioStreamPacketDescription!  

Structure keeps just single AudioStreamPacketDescription structure.
Then you use it in fillComplexCallback function:

outDataPacketDescription.memory.memory = convertInfo.packetDescriptions

So you are trying to set single AudioStreamPacketDescription structure to parameter outDataPacketDescription that expects array of AudioStreamPacketDescription structures (not just single instance).

This problem can be fixed by keeping and using array of AudioStreamPacketDescription structures.
Updated version of AudioConvertInfo structure:

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)

Updated version of fillComplexCallback function:

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)

Hope it will resolve your issue.

like image 74
Vlad Papko Avatar answered Oct 21 '22 22:10

Vlad Papko