0

現在、iOS で Audio Queue Services を使用する方法を学んでいます。このために、Audio Queue Services Programming Guide - Recording Audioに従いました。これは機能します。

コールバック関数がマイクから入力データを受け取ったときに、UI 要素 (パワー メーター) を更新したいと思います。ここで問題が発生します。

パワーメーターを更新するためにコールバック関数からビュー/ビューコントローラーに呼び出す良い方法がわかりません。私はこれを試しました:ガイドで説明されているstate を管理するカスタム構造体に、ビュー コントローラーへのポインターを追加しました。

struct AQRecorderState {
    AudioStreamBasicDescription  mDataFormat;                   // 2
    AudioQueueRef                mQueue;                        // 3
    AudioQueueBufferRef          mBuffers[kNumberBuffers];      // 4
    AudioFileID                  mAudioFile;                    // 5
    UInt32                       bufferByteSize;                // 6
    SInt64                       mCurrentPacket;                // 7
    bool                         mIsRunning;                    // 8
    void*                        mViewController; // <- I've added this line
};

記録を開始するときに、このポインターを初期化します。これは、スタート ボタンが TouchUp イベントを受け取ったときに呼び出されるビュー コントローラーのメソッドで行われます。

- (IBAction)startAudioRecording:(id)sender {

    struct AQRecorderState* aqData = createAQRecorderState();

    void* pViewControllerAsVoidPointer = (__bridge void*) self;
    aqData->mViewController = pViewControllerAsVoidPointer;

//...

構造体を割り当てる createAQRecorderState() メソッドは次のようになります。

struct AQRecorderState* createAQRecorderState() {
    struct AQRecorderState* pAqData = (struct AQRecorderState*) malloc(sizeof(AQRecorderState));

    initializeAQRecorderState(*pAqData); // sets members of the struct; does not set pointer to view controller

    return pAqData;
}

私の知る限り、記録を開始するときに作成した構造体のインスタンスそのものが、コールバック関数への後の呼び出しに配信されます。このため、ビュー コントローラーを呼び出すために、次のコードをコールバック関数に追加しました。

void HandleInputBuffer(
                       void                                 *aqData,
                       AudioQueueRef                        inAQ,
                       AudioQueueBufferRef                  inBuffer,
                       const AudioTimeStamp                 *inStartTime,
                       UInt32                               inNumPackets,
                       const AudioStreamPacketDescription   *inPacketDesc
                       ) {

//...

NSLog(@"interesting part start");

void* pViewControllerAsVoidPtr = pAqData->mViewController;
NSLog(@"localized pointer to void");

ViewController* pViewController = (__bridge ViewController*) pViewControllerAsVoidPtr;  //EXC_BAD_ACCESS
NSLog(@"localized pointer to ViewController");

//...
}

ただし、ブリッジされたポインター変換を行うと、上記のマークされた行のコールバック関数で EXC_BAD_ACCESS (コード = 1、アドレス = 0xffffffff) を取得します。次に、これをデバッガーで確認しましたが、実際にはメソッドの実行中に保存したアドレスを保持してpViewControllerAsVoidPtr いませんpAqData->mViewControllerstartAudioRecording:

そのポインターが変更されるのはなぜですか? または、代わりに: UI を更新するためにコールバック関数からビュー コントローラーに正しく呼び出す方法は?

4

1 に答える 1

0

私は自分の間違いを見つけました。それは私が録音オーディオキューを作成するステップを行う方法にあります。ガイドからコピーして貼り付けたとおりに実行します。

AudioQueueNewInput (                              // 1
    &aqData.mDataFormat,                          // 2
    HandleInputBuffer,                            // 3
    &aqData, //<------------------ HERE           // 4
    NULL,                                         // 5
    kCFRunLoopCommonModes,                        // 6
    0,                                            // 7
    &aqData.mQueue                                // 8
);

問題は、ガイドでは、変数aqDataが構造体であるため、ポインターに変換するために参照(先頭と符号)する必要があるのに対し、私の変数aqDataはすでに構造体へのポインターであるため、参照(先頭と記号)であるということでした。 sign)を「structへのポインタへのポインタ」に変更します。したがって、構造体のアドレスではなくポインタのアドレスを関数に渡しましたがAudioQueueNewInput(...)、これは間違っています。もちろん、この他の場所のメモリの内容は異なります。

コンパイラは、(void *)を予期しているため、この間違った型について文句を言いません。これは、構造体へのポインタへのポインタである(struct **)を含む任意のポインタです。

于 2012-11-29T12:01:49.400 に答える