Я хотел бы получить байт-буфер из аудиообъекта с помощью объекта OpenSL ES FileDescriptor, поэтому я могу повторно установить его в SimpleBufferQueue, вместо того, чтобы использовать SL-интерфейсы для воспроизведения / остановки / поиска файла.
Существуют три основные причины, по которым я хотел бы напрямую обращаться с образцами байтов:
Окей, поэтому оправдания завершены – вот что я пробовал – у меня есть структура 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» для получения более подробной информации.