5

私はAudioQueueServices APIを使用して、iPhoneのTCPソケット接続を介してサーバーからストリーミングされたオーディオを再生しています。ソケット接続から満たされたバッファーを再生できますが、AudioQueueにAudioQueueOutputCallback関数を呼び出させることができないようで、アイデアがありません。

ハイレベルなデザイン

  1. データはソケット接続からプレーヤーに渡され、メモリ内の循環バッファにすぐに書き込まれます。
  2. AudioQueueBuffersが使用可能になると、データは循環バッファーから使用可能なAudioQueueBufferにコピーされ、すぐに再キューイングされます。(または、私のコールバックが発生した場合)

何が起こるのですか

バッファはすべて正常にいっぱいになり、キューに入れられ、オーディオストリームがはっきりと聞こえます。テストでは、多数のバッファー(15)を使用し、それらすべてがシームレスに再生されますが、AudioQueueOutputCallbackが呼び出されることはないため、すべてが完全に機能しているように見えても、これらのバッファーを再キューイングすることはありません。コールバックが呼び出されないことを前提として、コールバックを待たずに、書き込まれたデータに基づいてバッファーのエンキューを駆動すると、オーディオストリームを無期限に再生し、バッファーを再利用して再エンキューすることができます。コールバックによって明示的に返されていました。その事実です。必要に応じてバッファを再利用しながらストリームを完全に再生できるため、最も混乱します。コールバックが呼び出されないのはなぜですか?

おそらく関連するコード

ストリームのフォーマットは、16ビットリニアPCM、8 kHz、モノラルです。

_streamDescription.mSampleRate = 8000.0f;
_streamDescription.mFormatID = kAudioFormatLinearPCM;
_streamDescription.mBytesPerPacket = 2;
_streamDescription.mFramesPerPacket = 1;
_streamDescription.mBytesPerFrame = sizeof(AudioSampleType);
_streamDescription.mChannelsPerFrame = 1;
_streamDescription.mBitsPerChannel = 8 * sizeof(AudioSampleType)
_streamDescription.mReserved = 0;
_streamDescription.mFormatFlags = (kLinearPCMFormatFlagIsBigEndian | 
                                   kLinearPCMFormatFlagIsPacked);

私のプロトタイプとコールバックの実装は次のとおりです。派手なものはなく、これまでに見たすべての例とほとんど同じです。

// Prototype, declared above the class's @implementation
void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer);

// Definition at the bottom of the file.
void AQBufferCallback(void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) {

    printf("callback\n");
    [(MyAudioPlayer *)inUserData audioQueue:inAudioQueue didAquireBufferForReuse:inAudioQueueBuffer];
}

次のようにAudioQueueを作成します。

OSStatus status = 0;
status = AudioQueueNewOutput(&_streamDescription, 
                             AQBufferCallback, // <-- Doesn't work...
                             self, 
                             CFRunLoopGetCurrent(),
                             kCFRunLoopCommonModes, 
                             0,
                             &_audioQueue);
if (status) {

    // This is not called...
    NSLog(@"Error creating new audio output queue: %@", [MyAudioPlayer stringForOSStatus:status]);
    return;
}

そして、私はこのようにバッファをエンキューします。この時点で、ローカルバッファにはコピー用の正しい量のデータが含まれていることがわかります。

memcpy(aqBuffer->mAudioData, localBuffer, kAQBufferSize);
aqBuffer->mAudioDataByteSize = kAQBufferSize;

OSStatus status = AudioQueueEnqueueBuffer(_audioQueue, aqBuffer, 0, NULL);
if (status) {
    // This is also not called.
    NSLog(@"Error enqueueing buffer %@", [MyAudioPlayer stringForOSStatus:status]);
}

私を救ってください。

4

2 に答える 2

7

これはメインスレッドまたはバックグラウンドスレッドで実行されますか?CFRunLoopGetCurrent()消える可能性のあるスレッド(スレッドプールなど)の実行ループを返す場合、またはを気にしない実行ループである場合は、おそらく適切ではありませんkCFRunLoopCommonModes

メインスレッドまたは制御可能で適切な実行ループを持つスレッドに変更CFRunLoopGetCurrent()するCFRunLoopGetMain()AudioQueueNewOutput()、実行されることを確認してください。CFRunLoopGetCurrent()

于 2011-09-28T07:40:28.543 に答える
-2

に変更selfしてみてください(void*)self。このような:

status = AudioQueueNewOutput(&_streamDescription, AQBufferCallback, (void*)self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &_audioQueue);

于 2011-09-27T22:10:26.280 に答える