1

そこで、すべてをセットアップして入力コールバックでオーディオ データを受信するという通常のプロセスを経て、入力キューに録音したいとしましょう。これをファイルに書き込む代わりに、どこかで簡単にバッファリングを開始し、入力キューの直後に実行を開始する出力キューに供給し、入力キューからバッファリングするデータを消費して再生したいと考えています。録音中のオーディオ。これは可能ですか?これを実装しようとしましたが、出力キューを開始する際に問題が発生しました。エラーが報告されずに初期化して開始しましたが、AudioQueueStart 関数を呼び出した後、提供された出力コールバックが呼び出されません。おそらくこれは私の実装の問題ですが、最初に行き止まりに陥っていないことを確認したかっただけです。

ありがとう

編集:コードが追加されました

コマンドラインアプリでこのPOCを実行しています。主に、レコーダーを初期化します。

    Recorder recorder = {0};

    AudioStreamBasicDescription asbd;
    memset(&asbd, 0, sizeof(asbd));

    asbd.mFormatID  = kAudioFormatLinearPCM;
    asbd.mSampleRate = SAMPLE_RATE;
    asbd.mBytesPerPacket = 4;
    asbd.mBytesPerFrame = 4;
    asbd.mChannelsPerFrame = 2;
    asbd.mBitsPerChannel = 16;
    asbd.mFramesPerPacket = 1;
    asbd.mFormatFlags = kAudioFormatFlagIsBigEndian |
    kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

    AudioQueueRef queue = {0};


    reportError(AudioQueueNewInput(&asbd, MyAQInputCallback, &recorder, NULL, NULL, 0, &queue), "AudioQueue Input Create");

     int bufferSize = 88200;

    for (int i = 0; i < BUFFER_COUNT; i++) {

        AudioQueueBufferRef retBuffer;
        reportError(AudioQueueAllocateBuffer(queue, bufferSize, &retBuffer), "Error Allocating Buffer");
        reportError(AudioQueueEnqueueBuffer(queue, retBuffer, 0, NULL), "Error enqueuing buffer");


    }

    recorder.running = YES;
    reportError(AudioQueueStart(queue, NULL), "Start Failed");
    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 3, false);

入ってくるデータを保持するためにグローバルな void ポインター配列を宣言しました。これは変更されます。実行できるかどうかを確認したかっただけです。

   static void *buffer[1000];

私の入力コールバック。これは特定のポイントまで呼び出されるため、レコーダーは正常に動作しています。これまでファイルなどに記録していました。

   static void MyAQInputCallback(void *inUserData,
                          AudioQueueRef inQueue,
                          AudioQueueBufferRef inBuffer,
                          const AudioTimeStamp *inStartTime,
                          UInt32 inNumPackets,
                          const AudioStreamPacketDescription *inPacketDesc)
{ 

Recorder *recorder = (Recorder *) inUserData;

buffer[globalBufferIndex] = (short *)inBuffer->mAudioData;
++globalBufferIndex;

if (globalBufferIndex == 1000) {
    globalBufferIndex = 0;
    clearBuffer();
}
if ( recorder->running ) {
    reportError(AudioQueueEnqueueBuffer(inQueue, inBuffer, 0, NULL), "CallbackEnqueue Failed");
}
}

基本的にここでの目標は、チャンクを取り出してバッファに格納することです。これは正常に機能すると思います。

プレーヤーが初期化されます。

Player player = {0};
AudioQueueRef que = {0};

reportError(AudioQueueNewOutput(&asbd, MyAQOutputCallback, &player, NULL, NULL, 0, &que), "New Output Error");

AudioQueueBufferRef buffers[BUFFER_COUNT];

 for (int i = 0; i < BUFFER_COUNT; ++i) {

        reportError(AudioQueueAllocateBuffer(que, bufferSize, &buffers[i]), "Error Buffer Allocating");

        MyAQOutputCallback(&player, que, buffers[i]);

  }

 reportError(AudioQueueStart(que, NULL), "Start Failed");

プレーヤーのコールバック:

static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef   inCompleteAQBuffer)
{ 

Player *player;

player = (Player *) inUserData;

short *chunk = (short *) inCompleteAQBuffer->mAudioData;
chunk = buffer[globalOutputBufferIndex];
globalOutputBufferIndex++;

AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, sizeof(chunk)/4, player->packetDescs);

}

目標は、グローバル バッファ内の内容をキューに格納して送信することです。

したがって、これが優れた構造ではないことはわかっていますが、実行すると、レコーダーが実行されて入力コールバックが呼び出され、データが保存されますが、プレーヤーの初期化が開始され、出力コールバックが 3 回呼び出されます ( my for ループ呼び出し)、二度と呼び出されません。getchar() を呼び出して、最後にアプリの終了をブロックします。ファイルから読み取って再生するようにプレーヤーを動作させましたが、明らかにこれは大きく異なりました。レコーダーは引き続き機能しますが、プレーヤーのコールバックは呼び出されません。説明に問題があるのではないかと思いましたが、割り当て中にエラーが報告されることはありません。ここでのガイダンスは素晴らしいでしょう。

ありがとう

4

1 に答える 1

2

誰もこれを知らないようですので、これを行うかなり良いサンプルプロジェクトへのリンクがあります:https ://github.com/alexbw/novocaine

于 2012-05-31T15:48:44.597 に答える