In iOS core audio there is the API AudioFileWritePackets that has a inPacketDescriptions parameter defined as
‘A pointer to an array of packet descriptions for the audio data.’
and it looks like this in the method signature:
const AudioStreamPacketDescription *inPacketDescriptions,
now the struct AudioStreamPacketDescription is defined as follows:
struct AudioStreamPacketDescription
{
SInt64 mStartOffset;
UInt32 mVariableFramesInPacket;
UInt32 mDataByteSize;
};
typedef struct AudioStreamPacketDescription AudioStreamPacketDescription;
I would like to know how to create and populate such a ‘pointer to an array of structs’, or even once given the variable, how to read it. Using the speakHere example from apple I put a breakpoint where I receive the variable and tried to dump all its contents to the log.. this is an example of an attempt:
void AQRecorder::printPacketDescriptionContents(const AudioStreamPacketDescription * inPacketDescriptions, UInt32 inNumberPackets)
{
for (int i = 0; i < inNumberPackets; ++i)
{
NSLog(@"\n----------------\n");
NSLog(@"this is packetDescriptionArray[%d].mStartOffset: %lld", i, (*inPacketDescriptions).mStartOffset);
NSLog(@"this is packetDescriptionArray[%d].mVariableFramesInPacket: %lu", i, (*inPacketDescriptions).mVariableFramesInPacket);
NSLog(@"this is packetDescriptionArray[%d].mDataByteSize: %lu", i, (*inPacketDescriptions).mDataByteSize);
NSLog(@"\n----------------\n");
}
}
any ideas?
Update: here is a sample log of me trying to mess around with it.. maybe it can help in the answer (notice at the bottom it keeps on appearing null.. it doesn’t make sense that the whole thing is just a pack of zeroes since it’s a variable returned by a callback that should be properly populated, also notice that it informs me about the number of packets I got back..).. also if i run the code with ((const AudioStreamPacketDescription *)(inPacketDescriptions +i))->mDataByteSize) i get a EXC_BAD_ACCESS error
(lldb) po **(inPacketDescriptions)
error: indirection requires pointer operand ('const AudioStreamPacketDescription' invalid)
error: 1 errors parsing expression
(lldb) po *(inPacketDescriptions)
(AudioStreamPacketDescription) $1 = [no Objective-C description available]
(lldb) po *(inPacketDescriptions).mStartOffset
error: member reference type 'const AudioStreamPacketDescription *' is a pointer; maybe you meant to use '->'?
error: indirection requires pointer operand ('SInt64' (aka 'long long') invalid)
error: 2 errors parsing expression
(lldb) po (*inPacketDescriptions).mStartOffset
(SInt64) $2 = 0 <nil>
(lldb) po (const AudioStreamPacketDescription *)(inPacketDescriptions +1)
(const class AudioStreamPacketDescription *) $3 = 0x00000010 [no Objective-C description available]
(lldb) po (const AudioStreamPacketDescription *)(inPacketDescriptions +1)->mStartOffset
error: Execution was interrupted, reason: Attempted to dereference an invalid pointer..
The process has been returned to the state before execution.
(lldb) po ((const AudioStreamPacketDescription *)(inPacketDescriptions +1))->mStartOffset
(SInt64) $5 = 0 <nil>
(lldb) po ((const AudioStreamPacketDescription *)(inPacketDescriptions +1))->mDataByteSize
(UInt32) $6 = 0 <nil>
(lldb) po ((const AudioStreamPacketDescription *)(inPacketDescriptions +100))->mDataByteSize
(UInt32) $7 = 0 <nil>
(lldb) po ((const AudioStreamPacketDescription *)(inPacketDescriptions +500))->mDataByteSize
(UInt32) $8 = 0 <nil>
(lldb) po inPacketDescriptions[0].mStartOffset
error: parent failed to evaluate: parent is NULL
(lldb)
also here is what it looks like in the XCode inspector:
I can’t remember an instance where this specific struct is ever populated by you, the client. You will need to create storage for these structs which you then pass across multiple calls in order to successfully deal with reading and writing audio data. Several non-PCM formats will need this information, depending on how the audio data has been stored.
Well, there are a handful of APIs in AudioFile I/O and AudioConvertor interfaces which use this structure. Basically, you don’t populate this type yourself. The basic flow goes like this:
(knowing the OP’s problem in some more detail) In many cases, you can avoid all this complexity and simply create an
ExtAudioFilerepresentation, and the specifykExtAudioFileProperty_ClientDataFormatfor your destination sample format — then the ExtAudioFile APIs will create an internal convertor on your behalf which will convert the input of an audio file of an arbitrary type to some specified PCM representation which you can use for the playback sample data. Implementing all this at this level is actually quite complex if you want to support many file formats. ExtAudioFile makes converting the sample data very easy — if that is an option and if it plays nicely with your streaming scenario.As far as the logging, well you’re attempting to print the fields of a NULL structure, from the looks of it.