Можно ли получить байтовый буфер непосредственно из аудиообъекта в OpenSL ES (для Android)?

Я хотел бы получить байт-буфер из аудиообъекта с помощью объекта OpenSL ES FileDescriptor, поэтому я могу повторно установить его в SimpleBufferQueue, вместо того, чтобы использовать SL-интерфейсы для воспроизведения / остановки / поиска файла.

Существуют три основные причины, по которым я хотел бы напрямую обращаться с образцами байтов:

  1. OpenSL использует слой AudioTrack для воспроизведения / остановки / etc для объектов Player. Это не только приводит к нежелательным накладным расходам, но также имеет несколько ошибок, а быстрые запуски / остановки игрока вызывают множество проблем.
  2. Мне нужно манипулировать байтовым буфером непосредственно для пользовательских эффектов DSP.
  3. Клипы, которые я собираюсь играть, небольшие, и все они могут быть загружены в память, чтобы избежать накладных расходов на ввод-вывод. Кроме того, включение моих собственных буферов позволит мне уменьшить время ожидания, записав 0 в выходной приемник и просто переключившись на выборку байтов при их воспроизведении, а не на STOPPING, PAUSING и PLAYING AudioTrack.

Окей, поэтому оправдания завершены – вот что я пробовал – у меня есть структура Sample, которая содержит, по существу, входную и выходную дорожки и массив байтов для хранения образцов. Ввод – мой проигрыватель 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); ственный // 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 дескриптора файла каждый раз. Вместо этого я хотел бы сохранить его в байтовом массиве и Enqueue на выходе, когда захочу.

    Декодирование на PCM доступно на уровне API 14 и выше.

    Когда вы создаете проигрыватель декодера, вам нужно установить обычную буферную очередь Android в качестве приемника данных:

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

    Для очереди декодеров вам нужно ввести в очередь набор пустых буферов в очередь буферов Android, которая будет заполнена данными PCM.

    Также вам нужно зарегистрировать обработчик обратного вызова с очередью декодера, который будет вызываться, когда данные PCM будут готовы. Обработчик обратного вызова должен обработать данные PCM, повторно поставить в очередь пустой буфер и затем вернуться. Приложение отвечает за отслеживание декодированных буферов; Список параметров обратного вызова не содержит достаточной информации, чтобы указать, какой буфер был заполнен, или какой буфер для очереди в очереди.

    Декодирование в PCM поддерживает приостановку и первоначальный поиск. Регулировка громкости, эффекты, цикличность и скорость воспроизведения не поддерживаются.

    Прочтите « Декодировать аудио в PCM от OpenSL ES для Android» для получения более подробной информации.