как читать / назначать элементы указателя, который указывает на массив структур в Stack Overflow

В iOS Core Audio есть API AudioFileWritePackets это имеет inPacketDescriptions параметр определяется как
‘Указатель на массив описаний пакетов для аудиоданных.’

и это выглядит так в сигнатуре метода:
const AudioStreamPacketDescription *inPacketDescriptions,

теперь структура AudioStreamPacketDescription определяется следующим образом:

struct  AudioStreamPacketDescription
{
SInt64  mStartOffset;
UInt32  mVariableFramesInPacket;
UInt32  mDataByteSize;
};
typedef struct AudioStreamPacketDescription AudioStreamPacketDescription;

Я хотел бы знать, как создать и заполнить такой «указатель на массив структур» или хотя бы однажды заданную переменную, как его прочитать. С использованием speakHere Пример от Apple, я поставил точку останова, где я получаю переменную и попытался сбросить все ее содержимое в журнал .. Это пример попытки:

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");

}
}

есть идеи?

Обновить: вот примерный журнал, в котором я пытаюсь возиться с этим … может быть, это может помочь в ответе (обратите внимание, что внизу он продолжает отображаться как ноль … это не имеет смысла, что все это просто пачка нулей) так как это переменная, возвращаемая обратным вызовом, который должен быть правильно заполненным, также обратите внимание, что он информирует меня о количестве пакетов, которые я получил ..) .. также, если я запускаю код с ((const AudioStreamPacketDescription *)(inPacketDescriptions +i))->mDataByteSize) я получаю ошибку EXC_BAD_ACCESS

(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)

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

1

Решение

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

Я хотел бы знать, как создать и заполнить такой «указатель на массив структур» или хотя бы однажды заданную переменную, как его прочитать.

Ну, есть несколько API в интерфейсах AudioFile I / O и AudioConvertor, которые используют эту структуру. По сути, вы не заполняете этот тип самостоятельно. Основной поток выглядит так:

// this is not for PCM audio data
//
// we'll read up to 8 packets at a time:
const size_t MaxPacketsToRead(8);

// allocate MaxPacketsToRead ASPDs on the stack:
AudioStreamPacketDescription aspds[MaxPacketsToRead];

// audio file read function:
AudioFileID inAudioFile = ...;
Boolean inUseCache = ...;
UInt32 outNumBytes = ...;
AudioStreamPacketDescription* outPacketDescriptions(aspds);
SInt64 inStartingPacket = ...;
UInt32 ioNumPackets = MaxPacketsToRead; // << you may not get all the packets
// you request, but this sets the
// upper limit.
void* outBuffer = ...;OSStatus result(AudioFileReadPackets(inAudioFile,
inUseCache,
&outNumBytes,
outPacketDescriptions,
inStartingPacket,
&ioNumPackets,
outBuffer
));

if (noErr != result) {
...uh-oh...
}

// *now* we know that we have ioNumPackets worth of valid ASPDs,
// populated by the reader. and we have the associated audio data
// in other parameters.
// we can now safely pass all this information off to a function which
// reads the ASPDs, such as AudioFileWritePackets.

(зная проблему ОП более подробно) Во многих случаях вы можете избежать всей этой сложности и просто создать ExtAudioFile представление и указать kExtAudioFileProperty_ClientDataFormat для целевого формата семпла — тогда API-интерфейсы ExtAudioFile создадут от вашего имени внутренний преобразователь, который преобразует входной аудиофайл произвольного типа в некоторое указанное представление PCM, которое вы можете использовать для данных семпла воспроизведения. Реализация всего этого на этом уровне на самом деле довольно сложна, если вы хотите поддерживать множество форматов файлов. ExtAudioFile делает преобразование данных примера очень простым — если это вариант и если он хорошо сочетается с вашим сценарием потоковой передачи.

Что касается ведения журнала, вы пытаетесь напечатать поля структуры NULL, судя по всему.

1

Другие решения

Объявить массив AudioStreamPacketDescription:

AudioStreamPacketDescription descriptions[10];

/* Populate 'descriptions' */
descriptions[0].mVariableFramesInPacket = 4; /* For example. */

затем передайте его функции:

/* 'a' is an instance of AQRecorder. */
a.printPacketDescriptionContents(descriptions, 10);

когда массив передается функции, он распадается на указатель (на первый элемент массива).

Пример printPacketDescriptionContents() только доступ к первому элементу массива inNumberPackets раз: вам нужно получить доступ к каждому элементу:

NSLog(@"this is packetDescriptionArray[%d].mStartOffset: %lld",
i,
inPacketDescriptions[i].mStartOffset);
1