是否有可能从OpenSL ES(Android版)的音频资产得到一个字节的缓冲区直接? [英] Is it possible to get a byte buffer directly from an audio asset in OpenSL ES (for Android)?

查看:788
本文介绍了是否有可能从OpenSL ES(Android版)的音频资产得到一个字节的缓冲区直接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想获得使用该OpenSL ES FileDescriptor对象的音频资产一个字节的缓冲区,这样我就可以反复排队到一个SimpleBufferQueue,而不是使用SL接口来播放/停止/搜索该文件。

I would like to get a byte buffer from an audio asset using the OpenSL ES FileDescriptor object, so I can enqueue it repeatedly to a SimpleBufferQueue, instead of using SL interfaces to play/stop/seek the file.

有三个主要的原因,我想直接管理的样本字节:

There are three main reasons why I would like to manage the sample bytes directly:

  1. 在OpenSL采用AudioTrack层,播放/停止/等供玩家对象。这不仅引入不希望的开销,但它也有若干缺陷,和快速启动/播放器的停止会导致很多问题。
  2. 我需要直接操纵字节的缓冲区定制的DSP效果。
  3. 我要玩的剪辑小,都可以加载到内存中,避免文件I / O开销。另外,我排入队列自己的缓冲可以让我通过写0到输出水槽,并简单地切换到采样时,他们是在玩,而不是停止,暂停和播放AudioTrack字节,以减少等待时间。

好了,所以理完成 - 这是我已经试过 - 我有一个样品结构,其中包含,本质上,输入和输出的轨道,和一个字节数组来保存样品。输入的是我的FileDescriptor播放机,而输出是一个SimpleBufferQueue对象。这里是我的结构:

Okay, so justifications complete - here's what I've tried - I have a Sample struct which contains, essentially, an input and output track, and a byte array to hold the samples. The input is my FileDescriptor player, and the output is a SimpleBufferQueue object. Here's my struct:

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 - 荷兰国际集团的内存为我字节的缓冲区以

after initializing a file player fdPlayerObject, and malloc-ing memory for my byte buffer with

sample->buffer = malloc(sizeof(short)*sample->totalSamples);

我收到了BufferQueue接口

I'm getting its BufferQueue interface with

// 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));

不过,这会导致我的应用程序,冻结和关闭。这里不对劲。 同时,我想preFER每次都没有拿到样品从文件描述的BufferQueue。相反,我想永久地存放在一个字节数组,排队,要输出时,我喜欢。

However, this causes my app to freeze and shut down. Something is wrong here. Also, I would prefer to not get the samples from the File Descriptor's BufferQueue each time. Instead, I'd like to permanently store it in a byte array, and Enqueue that to the output whenever I like.

推荐答案

解码PCM可在API级别14或更高。

Decoding to PCM is available at API level 14 and higher.

在创建日codeR球员,你需要设置的Andr​​oid简单的缓冲队列中的数据接收器:

When you create decoder player you need set Android simple buffer queue as the data sink:

// For init use something like this:
SLDataLocator_AndroidFD locatorIn = {SL_DATALOCATOR_ANDROIDFD, decriptor, start, length};
SLDataFormat_MIME dataFormat = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&locatorIn, &dataFormat};

SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataSink audioSnk = { &loc_bq, NULL };

const SLInterfaceID ids[2] = {SL_IID_PLAY, SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

SLresult result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(sample->fdPlayerObject), &outputAudioSrc, &audioSnk, 2, ids1, req1);

有关德codeR队列,你需要排队一组空缓冲区到Android简单的缓冲队列,这将充满PCM数据。

For decoder queue you need enqueue a set of empty buffers to the Android simple buffer queue, which will be filled with PCM data.

此外,你需要注册,将被调用时,PCM数据将准备去codeR队列中的回调处理程序。回调处理程序应该处理的PCM数据,重新入队现在空缓冲区,然后返回。该应用程序负责跟踪德codeD缓冲区;回调参数列表不包含足够的信息,以指示哪一个缓冲区填满或缓冲区排队下一个。

Also you need register a callback handler with the decoder queue which will be called when PCM data will be ready. The callback handler should process the PCM data, re-enqueue the now-empty buffer, and then return. The application is responsible for keeping track of decoded buffers; the callback parameter list does not include sufficient information to indicate which buffer was filled or which buffer to enqueue next.

德code到PCM支持暂停和初始找。音量控制,效果,不支持循环和回放速度。

Decode to PCM supports pause and initial seek. Volume control, effects, looping, and playback rate are not supported.

德code音频PCM 从的 OpenSL ES为Android 了解详细信息。

这篇关于是否有可能从OpenSL ES(Android版)的音频资产得到一个字节的缓冲区直接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆