私は現在、iOS で IMA-ADPCM オーディオ データを TCP ソケット経由で読み取り、それを PCM に変換してストリームを再生するアプリを開発しています。この段階で、ストリームからデータをプルする (プッシュに反応すると言うべきか) クラスを完成させ、それを PCM にデコードしました。また、Audio Queue クラスをセットアップし、テスト トーンを再生します。サポートが必要なのは、Audio Queue にデータを渡す最善の方法です。
オーディオ データは、ADPCM デコーダーから 8 Khz 16 ビット LPCM として 1 チャンク 640 バイトで出力されます。(元は 160 バイトの ADPCM データですが、640 バイトに解凍されます)。これは uint_8t 配列として関数に入り、NSData オブジェクトを渡します。ストリームは「プッシュ」ストリームであるため、オーディオが送信されるたびにオブジェクトが作成/フラッシュされます。
-(NSData*)convertADPCM:(uint8_t[]) adpcmdata {
Audio Queue コールバックはもちろん、実行ループの各パスでデータを検索するプル関数です。実行される各パスで:
-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {
私はこれに数日間取り組んできましたが、PCM 変換は非常に負担が大きく、2 つの間のデータを橋渡しする最善の方法を頭の中で組み立てるのに少し苦労しています。データを作成しているわけではありません。データがプッシュされているのではなく、単純にデータ作成を fillbuffer ルーチンに組み込むことができます。
uint16_t[] で 0.5 秒の循環バッファーをセットアップしました ~ しかし、脳が疲れ果てており、バッファーからプッシュおよびプルする適切な方法を見つけることができなかったと思います。 .
私は主に Android でプロジェクトを完了しましたが、AudioTrack は Core-Audio Queues とはまったく異なる獣であることがわかりました。
この段階で、Adamson と Avila による Learning Core Audio のコピーを手に取り、これがコア オーディオの謎を解こうとしている人にとって優れたリソースであることがわかったと言いたいと思います。
更新: バッファ管理コードは次のとおりです。
-(OSStatus) fillBuffer: (AudioQueueBufferRef) buffer {
int frame = 0;
double frameCount = bufferSize / self.streamFormat.mBytesPerFrame;
// buffersize = framecount = 8000 / 2 = 4000
//
// incoming buffer uint16_t[] convAudio holds 64400 bytes (big I know - 100 x 644 bytes)
// playedHead is set by the function to say where in the buffer the
// next starting point should be
if (playHead > 99) {
playHead = 0;
}
// Playstep factors playhead to get starting position
int playStep = playHead * 644;
// filling the buffer
for (frame = 0; frame < frameCount; ++frame)
// framecount = 4000
{
// pointer to buffer
SInt16 *data = (SInt16*)buffer->mAudioData;
// load data from uint16_t[] convAudio array into frame
(data)[frame] = convAudio[(frame + playStep)];
}
// set buffersize
buffer->mAudioDataByteSize = bufferSize;
// return no Error - Osstatus will return an error otherwise if there is one. (I think)
return noErr;
}
私が言ったように、私がこれを書いたとき、私の脳はぼんやりしていました。
上記のコードは、コールバックによって呼び出されます。
static void MyAQOutputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer)
{
soundHandler *sHandler = (__bridge soundHandler*)inUserData;
CheckError([sHandler fillBuffer: inCompleteAQBuffer],
"can't refill buffer",
"buffer refilled");
CheckError(AudioQueueEnqueueBuffer(inAQ,
inCompleteAQBuffer,
0,
NULL),
"Couldn't enqueue buffer (refill)",
"buffer enqued (refill)");
}
convAudio配列側では、ログに記録するためにそれをダンプしましたが、循環的にいっぱいになり、再いっぱいになっているので、少なくともそのビットが機能していることがわかります。