マイクからの生の入力サンプルを処理する必要がある CoreAudio アプリケーションを構築しています。2 つのスレッドを使用します。1 つのスレッドはマイク入力からサンプルを生成し、もう 1 つのスレッドはサンプルを消費します。これらのスレッドは、(うまく機能する) 循環バッファーを共有します。その実装は、Github から取得しました (良い例は、著者のブログにあります)。
私の問題の最小限の例として、Github に小さな XCode プロジェクトをまとめたので、完全なコードを見ることができます。アプリはマイク サンプルを循環バッファーに入れ、別のスレッドからバッファーを読み取ります。消費スレッドは、500 サンプルの平均整流値(ARV) を計算し、ARV をコンソールに出力します。
iOS シミュレーター (5.1) でアプリを実行すると、すべて正常に動作し、目的の出力が得られます。
2012-08-21 20:58:31.882 BufferedSamples[23505:6003] 88
2012-08-21 20:58:31.890 BufferedSamples[23505:6003] 108
2012-08-21 20:58:31.890 BufferedSamples[23505:6003] 137
2012-08-21 20:58:31.891 BufferedSamples[23505:6003] 137
2012-08-21 20:58:31.892 BufferedSamples[23505:6003] 106
2012-08-21 20:58:31.901 BufferedSamples[23505:6003] 140
...
代わりにデバイス (iPhone 3/3GS/4 を試しました) でアプリを実行しようとすると、ポインターEXC_BAD_ACCESS
が原因で実行時にエラーが発生します。NULL
したがってNULL
、CoreAudio コールバック関数 (ファイル内DummyRecorder.m
)にポインターのチェックを追加しました。
// render samples into buffer
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mDataByteSize = inNumberFrames * kTwoBytesPerSInt16;
bufferList.mBuffers[0].mData = NULL;
AudioUnitRender(dummyRecorder->audioUnit, ioActionFlags, inTimeStamp, kInputBus, inNumberFrames, &bufferList);
// move samples to ring buffer
if (bufferList.mBuffers[0].mData != NULL)
TPCircularBufferProduceBytes(&dummyRecorder->buffer, bufferList.mBuffers[0].mData, bufferList.mBuffers[0].mDataByteSize);
else
NSLog(@"null pointer");
シミュレーターでアプリを実行すると、目的の出力が得られますが、デバイスでは次のようになります。
2012-08-21 21:15:38.903 BufferedSamples[544:3b03] null pointer
2012-08-21 21:15:38.926 BufferedSamples[544:3b03] null pointer
2012-08-21 21:15:38.949 BufferedSamples[544:3b03] null pointer
2012-08-21 21:15:38.972 BufferedSamples[544:3b03] null pointer
2012-08-21 21:15:38.996 BufferedSamples[544:3b03] null pointer
2012-08-21 21:15:39.019 BufferedSamples[544:3b03] null pointer
...
シミュレーターでは CoreAudio がバッファーを正しく割り当てて満たすのに、デバイスではバッファーをそのままにしておくことができるのはなぜですか? 私は何を逃したのですか?
私の例の完全なコードは、Github で見つけることができます。
編集
提案どおり、CoreAudio の呼び出し後にエラーをチェックするメソッドを追加しました。@MichaelTyson
今、私はコールバックでこれをやっています:
OSStatus err = AudioUnitRender(dummyRecorder->audioUnit, ioActionFlags, inTimeStamp, kInputBus, inNumberFrames, &bufferList);
// move samples to ring buffer
if (checkResult(err, "AudioUnitRender"))
TPCircularBufferProduceBytes(&dummyRecorder->buffer, bufferList.mBuffers[0].mData, bufferList.mBuffers[0].mDataByteSize);
Github のコードも更新しました。シミュレーターでアプリを実行してもエラーは発生しませんが、デバイスで実行すると次のエラーが発生します。
2012-08-22 11:19:49.248 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
2012-08-22 11:19:49.271 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
2012-08-22 11:19:49.294 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
2012-08-22 11:19:49.317 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
2012-08-22 11:19:49.341 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
2012-08-22 11:19:49.364 BufferedSamples[637:3b03] /DummyRecorder.m:50: AudioUnitRender result -50 FFFFFFCE Œˇˇˇ
...