そこで、すべてをセットアップして入力コールバックでオーディオ データを受信するという通常のプロセスを経て、入力キューに録音したいとしましょう。これをファイルに書き込む代わりに、どこかで簡単にバッファリングを開始し、入力キューの直後に実行を開始する出力キューに供給し、入力キューからバッファリングするデータを消費して再生したいと考えています。録音中のオーディオ。これは可能ですか?これを実装しようとしましたが、出力キューを開始する際に問題が発生しました。エラーが報告されずに初期化して開始しましたが、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() を呼び出して、最後にアプリの終了をブロックします。ファイルから読み取って再生するようにプレーヤーを動作させましたが、明らかにこれは大きく異なりました。レコーダーは引き続き機能しますが、プレーヤーのコールバックは呼び出されません。説明に問題があるのではないかと思いましたが、割り当て中にエラーが報告されることはありません。ここでのガイダンスは素晴らしいでしょう。
ありがとう