Воспроизведение звука PCM WAVE из памяти с помощью OpenSL на Android

Я пытаюсь настроить OpenSL AudioPlayer для использования памяти, выделенной для воспроизведения файла wav. Я хочу сделать это, чтобы иметь несколько аудиоплееров, которые совместно используют одни и те же данные и экономят память.

Я пытался дать openSL весь файл и сказать, что это WAVE с format_mime

 SLDataLocator_Address loc_fd = {SL_DATALOCATOR_ADDRESS, data, size};
SLDataFormat_MIME format_mime = { SL_DATAFORMAT_MIME, (SLchar*)"audio/x-wav",SL_CONTAINERTYPE_WAV};
SLDataSource audioSrc = { &loc_fd, &format_mime };
// configure audio sink
SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX,outputMixObject };
SLDataSink audioSnk = { &loc_outmix, 0 };
// create audio player
const SLInterfaceID ids[2] = { SL_IID_SEEK, SL_IID_PLAYBACKRATE };
const SLboolean req[2] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE };
result = (*engineEngine)->CreateAudioPlayer(engineEngine,&uriPlayerObject[cntSOUND],&audioSrc, &audioSnk, 0, ids, req);

и я сам проанализировал данные WAVE и загрузил format_pcm

SLDataFormat_PCM format_pcm;
format_pcm.formatType = SL_DATAFORMAT_PCM;
char* wavParser = isWAVE(data);
if(wavParser == NULL)
{
    Log("NOT A WAVE!");
    return -1;
}
char* fmtChunk = getChunk("fmt ", data, size);
parsefmtChunk(fmtChunk, &format_pcm);
char* dataChunk = getChunk("data",data, size);
dataChunk += 4;
unsigned int dataSize = *((unsigned int*)dataChunk);
dataChunk += 4;
format_pcm.channelMask = 0;
format_pcm.containerSize = 16;
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
loc_fd.pAddress = dataChunk;
loc_fd.length = dataSize;

Функция parsefmtChunk

void parsefmtChunk(char* fmtchunk, SLDataFormat_PCM* pcm)
{
char* data = fmtchunk + 8;
unsigned short audioFormat = *((unsigned short*)data);
if(audioFormat != 1)
{
    Log("Not PCM!");
    Log("Reached Line:%d in File %s", __LINE__, __FILE__);
    return;
}
data += 2;
pcm->numChannels = *((unsigned short*)data);
data += 2;
pcm->samplesPerSec = *((unsigned int*)data);
data += 4;
//Byte Rate
data += 4;
//Block Align
data += 2;
//BitsPerSample
pcm->bitsPerSample = *((unsigned short*)data);

(Предполагается ли, что Byte Rate и Block Align каким-то образом используются для заполнения структуры PCM?)

но всякий раз, когда я создаю аудиоплеер, я получаю SL_RESULT_CONTENT_UNSUPPORTED

Это то, что я регистрирую в своей функции parsefmt. Каналы: 2 SamplePerSec: 44100 битPerSample: 16


person agoaj    schedule 28.09.2013    source источник


Ответы (2)


из android-ndk-r8b/docs/opensles/index.html

формат данных ИКМ

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

Таким образом, SLDataFormat_PCM НЕ МОЖЕТ использоваться с SLDataLocator_Address, как я предполагал.

Вместо этого я могу делать то, что хочу, с буферной очередью, используя только одну большую очередь, например

bufferqueueitf->Enqueue(bufferqueueitf,dataChunk,dataSize);
person agoaj    schedule 28.09.2013

Вы пробовали это?

SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};

Реализация OpenSL ES для Android не полностью совместима и http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/ рекомендует следующее:

Реализация OpenSL ES для Android требует, чтобы mimeType был инициализирован либо значением NULL, либо допустимой строкой UTF-8, и чтобы containerType был инициализирован допустимым значением. При отсутствии других соображений, таких как переносимость на другие реализации или формат содержимого, который не может быть идентифицирован по заголовку, мы рекомендуем установить для параметра mimeType значение NULL, а для containerType — значение SL_CONTAINERTYPE_UNSPECIFIED.

Кроме того, убедитесь, что вы указываете действительный URI.

person HerrLip    schedule 28.09.2013
comment
Не использовать URI (хотя в спецификации это не упоминается, MIME работает и для файловых дескрипторов Android) - person agoaj; 29.09.2013