1

iOS コア オーディオには、 「オーディオ データのパケット記述の配列へのポインター」として定義されたパラメーターを持つAPI AudioFileWritePacketsがあります。inPacketDescriptions

メソッドシグネチャでは次のようになります。
const AudioStreamPacketDescription *inPacketDescriptions,

現在、構造体 AudioStreamPacketDescription は次のように定義されています。

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

そのような「構造体の配列へのポインター」を作成して設定する方法、または変数が与えられたら、それを読み取る方法を知りたいです。Apple のspeakHereの例を使用して、変数を受け取るブレークポイントを設定し、そのすべての内容をログにダンプしようとしました。これは試行の例です。

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

    }        
}

何か案は?

更新:これは私がそれをいじろうとしているサンプルログです..多分それは答えに役立つかもしれません(一番下にnullが表示され続けることに注意してください..全体が単なるパックであることは意味がありませんこれはコールバックによって返される変数であるため、適切に入力する必要があります。また、返されたパケットの数についても通知されることに注意してください......また、コードを実行すると((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インスペクターでの表示は次のとおりです。ここに画像の説明を入力

4

2 に答える 2

1

次の配列を宣言しますAudioStreamPacketDescription

AudioStreamPacketDescription descriptions[10];

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

次に、それを関数に渡します。

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

配列が関数に渡されると、ポインター (配列の最初の要素) に減衰します。

この例printPacketDescriptionContents()では、配列inNumberPacketstimes の最初の要素にのみアクセスしています。各要素にアクセスする必要があります。

NSLog(@"this is packetDescriptionArray[%d].mStartOffset: %lld",
      i,
      inPacketDescriptions[i].mStartOffset);
于 2012-09-25T07:57:22.960 に答える
1

この特定の構造体がクライアントであるあなたによって設定されたインスタンスを思い出せません。オーディオ データの読み取りと書き込みを正常に処理するには、これらの構造体用のストレージを作成して複数の呼び出しに渡す必要があります。オーディオ データの保存方法に応じて、いくつかの非 PCM 形式でこの情報が必要になります。

そのような「構造体の配列へのポインター」を作成して設定する方法、または変数が与えられたら、それを読み取る方法を知りたいです。

さて、AudioFile I/O および AudioConvertor インターフェイスには、この構造を使用する API がいくつかあります。基本的に、このタイプを自分で設定することはありません。基本的な流れは次のようになります。

// 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.

(OPの問題をもう少し詳しく知っている)多くの場合、この複雑さをすべて回避し、単にExtAudioFile表現を作成kExtAudioFileProperty_ClientDataFormatし、目的のサンプル形式を指定することができます.ExtAudioFile APIはあなたに代わって内部コンバーターを作成します.任意のタイプのオーディオ ファイルの入力を、サンプル データの再生に使用できる特定の PCM 表現に変換します。多くのファイル形式をサポートしたい場合、このレベルでこれらすべてを実装することは、実際には非常に複雑です。ExtAudioFile を使用すると、サンプル データの変換が非常に簡単になります (それがオプションであり、ストリーミング シナリオでうまく機能する場合)。

ロギングに関しては、見た目から NULL 構造体のフィールドを出力しようとしています。

于 2012-09-25T09:29:50.900 に答える