Android NDK: работа с OpenAL и постепенная подгрузка WAV

В прошлой статье показал, как можно работать с WAV и Ogg форматами в ndk с помощью OpenaAL. Вот только в той реализации файлы целиком в память грузились. Кое-что дописал для работы с WAV, теперь файл можно грузить кусками по мере необходимости.

Вообще, изначально пытался создать несколько буферов, а потом, когда заканчивает играть один, переключался на другой. При таком способе в момент переключения между буферами слышен щелчок, так что этот вариант пришлось сразу отбросить. Как оказалось, в OpenAL можно сразу очередь буферов настроить (надо приучить себя сначала документацию читать, перед тем, как свои костыли городить).

Небольшое отступление

Этот код по работе с OpenAL уже вышел за рамки туториала, поэтому решил как отдельный проект сделать. Может позже по фану и работу с другими форматами сделаю (с тем же mp3, к примеру). Сам проект можно посмотреть на github’е.

Для стриминга начальную инициализацию необходимо слегка поменять:

//создаём сорс и буферыalGenBuffers(BUFF_COUNT, buffers);alGenSources(1, &source);if(alGetError() != AL_NO_ERROR){  LOGI("Error generating :(\n");  return;}//создаём буферыfor(int i=0;i<BUFF_COUNT;++i)  creatBuffer(i);if(alGetError() != AL_NO_ERROR) {   LOGI("Error loading :(\n");  return ;}//ставим в очередь к источнику source буферыalSourceQueueBuffers(source, BUFF_COUNT, buffers);if(alGetError() != AL_NO_ERROR) {  LOGI("Error alSourceQueueBuffers :(\n");  return;}

Создаём столько буферов, сколько нам необходимо.

void OALWav ::creatBuffer(int index){  //определям размер данных для чтения  int size = Min(BUFFER_SIZE, header.dataSize -curPos);  //читаем чанки  unsigned  char * data = readRiffs(size);  if(!data)return;  //создаём буферы  createBufferFromWave(data,size, index);}

Ну и ещё метод по чтению куска файла:

Чтение куска WAV файла

unsigned char* OALWav::readRiffs(int size){if(curPos>=header.dataSize) {f.close();return 0;}if (!(// Заголовки должны быть валидны.// Проблема в том, что не всегда так.// Многие конвертеры недобросовестные пихают в эти заголовки свои логотипы =/memcmp("RIFF",header.riff,4) ||memcmp("WAVE",header.wave,4) ||memcmp("fmt ",header.fmt,4)  ||memcmp("data",header.data,4))){if (buf){int r = f.read(buf,size,1);if(r){curPos +=r;return buf;}free(buf);}}f.close();return 0;}

Теперь остаётся только проиграть аудио файл:

//начинаем игратьalSourcePlay(source);//если ещё не весь файл прочиталиwhile(curPos<header.dataSize) {ALint val;ALuint buffer;//проверяем, какие буферы уже отыгралиalGetSourcei(source, AL_BUFFERS_PROCESSED, &val);if(val <= 0)continue;//для каждого проигранного буфераwhile(val--) {//размер данных для чтенияint size = Min(BUFFER_SIZE, header.dataSize -curPos);//читаем новые чанкиunsigned char * data = readRiffs(size);//дропаем из очереди отыгравший буферalSourceUnqueueBuffers(source, 1, &buffer);//создаём его по новой с новыми чанкамиalBufferData(buffer, format, data, size, header.samplesPerSec);//ставим в очередь к источнику source буферыalSourceQueueBuffers(source, 1, &buffer);if(alGetError() != AL_NO_ERROR) {LOGI("Error buffering :(\n");}}}

Надо бы тоже самое и для Ogg сделать, как время будет. Сам проект, как уже выше писал, можно посмотреть на github’е.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *