OpenSL ES FileDescriptorオブジェクトを使用してオーディオアセットからバイトバッファを取得したいので、SLインターフェイスを使用してファイルを再生/停止/シークする代わりに、SimpleBufferQueueに繰り返しエンキューできます。OpenSL ES(Android用)のオーディオアセットから直接バイトバッファを取得することはできますか?
私はサンプルを管理したい理由を三つの主要な理由がありますが、直接バイト:
- OpenSLは、プレーヤーオブジェクトの/停止/などを再生するためにAudioTrack層を使用しています。これにより、不必要なオーバーヘッドが発生するだけでなく、いくつかのバグがあり、プレーヤーの急速な開始/停止によって多くの問題が発生します。
- カスタムDSPエフェクトのためにバイトバッファを直接操作する必要があります。
- 私が再生しようとしているクリップは小さく、ファイルのI/Oオーバーヘッドを避けるためにすべてメモリにロードできます。さらに、独自のバッファをエンキューすることで、出力シンクに0を書き込んでレイテンシーを減らし、AudioTrackを停止、一時停止、再生するのではなく、再生中に単にサンプルバイトに切り替えることができます。完全
わかりましたので、正当性は - ここで私が試したものだ - 私は、基本的に、入力と出力のトラックが含まれていサンプル構造体、およびサンプルを保持するためにバイト配列を持っています。入力は私のFileDescriptorプレーヤーで、出力はSimpleBufferQueueオブジェクトです。ここに私の構造体です:
typedef struct Sample_ {
// buffer to hold all samples
short *buffer;
int totalSamples;
SLObjectItf fdPlayerObject;
// file descriptor player interfaces
SLPlayItf fdPlayerPlay;
SLSeekItf fdPlayerSeek;
SLMuteSoloItf fdPlayerMuteSolo;
SLVolumeItf fdPlayerVolume;
SLAndroidSimpleBufferQueueItf fdBufferQueue;
SLObjectItf outputPlayerObject;
SLPlayItf outputPlayerPlay;
// output buffer interfaces
SLAndroidSimpleBufferQueueItf outputBufferQueue;
} Sample;
sample->buffer = malloc(sizeof(short)*sample->totalSamples);
でfdPlayerObjectファイルプレーヤーを初期化し、そして私のバイトのバッファのためのmalloc-INGのメモリの後、私は
// get the buffer queue interface
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue));
とのBufferQueueインターフェイスを取得しています 出力プレーヤー:
をインスタンス化します。// create audio player for output buffer queue
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->outputPlayerObject), &outputAudioSrc, &audioSnk,
1, ids1, req1);
// realize the output player
result = (*(sample->outputPlayerObject))->Realize(sample->outputPlayerObject, SL_BOOLEAN_FALSE);
assert(result == SL_RESULT_SUCCESS);
// get the play interface
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_PLAY, &(sample->outputPlayerPlay));
assert(result == SL_RESULT_SUCCESS);
// get the buffer queue interface for output
result = (*(sample->outputPlayerObject))->GetInterface(sample->outputPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(sample->outputBufferQueue));
assert(result == SL_RESULT_SUCCESS);
// set the player's state to playing
result = (*(sample->outputPlayerPlay))->SetPlayState(sample->outputPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(result == SL_RESULT_SUCCESS);
私はサンプルを再生したい場合は、私が使用しています:
Sample *sample = &samples[sampleNum];
// THIS WORKS FOR SIMPLY PLAYING THE SAMPLE, BUT I WANT THE BUFFER DIRECTLY
// if (sample->fdPlayerPlay != NULL) {
// // set the player's state to playing
// (*(sample->fdPlayerPlay))->SetPlayState(sample->fdPlayerPlay, SL_PLAYSTATE_PLAYING);
// }
// fill buffer with the samples from the file descriptor
(*(sample->fdBufferQueue))->Enqueue(sample->fdBufferQueue, sample->buffer,sample->totalSamples*sizeof(short));
// write the buffer to the outputBufferQueue, which is already playing
(*(sample->outputBufferQueue))->Enqueue(sample->outputBufferQueue, sample->buffer, sample->totalSamples*sizeof(short));
をしかし、これは私のアプリがフリーズし、シャットダウンする原因となります。ここは何かがおかしい。 また、私はファイルディスクリプタのBufferQueueから毎回サンプルを取得したくないと思います。代わりに、私は永久にそれをバイト配列に格納したいと思います。
こんにちはkhiner、Javaバイトまたは短い配列のアセットフォルダから.wavファイルを読み込み、これをさらに処理するのに役立ちますか? –
私がどれくらい助けてくれるのかよく分かりませんが、記録のためだけにNDKを使っていますか?あなたのコードはC++になっているのですか? – Erhannis
はい、私はNDKを使用していますが、これは実際には純粋なCです。この質問は長い間歯に入っています。私はこれに関して数多くの進歩を遂げており、まともな答えを加えようとしています。 – khiner