我想摆脱使用OpenSL ES FileDescriptor对象音频资产一个字节的缓冲区,这样我就可以反复排队到一个SimpleBufferQueue,而不是使用SL接口来播放/停止/搜索文件。
有几个原因,我想直接管理的样本字节主要原因有三:
- OpenSL使用一个AudioTrack层播放/停止/等供玩家对象。 这不仅引入不必要的开销,但同时也存在一些bug,以及快速启动/播放器的停止导致很多问题。
- 我需要直接操纵字节的缓冲区定制的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;
初始化文件播放fdPlayerObject和malloc的-ING内存,以便在我的字节的缓冲区后
sample->buffer = malloc(sizeof(short)*sample->totalSamples);
我得到它的BufferQueue接口
// get the buffer queue interface
result = (*(sample->fdPlayerObject))->GetInterface(sample->fdPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(sample->fdBufferQueue));
然后,我实例化一个输出的球员 :
// 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每次拿到样品。 相反,我想永久将其存储在一个字节数组,排队,要输出时,我喜欢。