Добрался в своей программе до звука. В NDK есть OpenSL ES. Но, насколько я понял, эта библиотека есть, начиная с 9-й платформы. Будет ли работать в более ранних версиях (хотя бы начиная с Android 2.1, а лучше 1.6)? Если нет, то как делается звук в версиях < 2.3 (нативный код естественно)?
Можно заюзать OpenAL. Будет работать с 2.1 (может и на более ранних - я сам не проверял на них).
OpenAL на андройде - обертка над джавовым AuidoTrack (через JNI)
Кроме AudioTrack до 2.1 ничего нет
OpenAL на андройд: http://pielot.org/2010/12/14/openal-on-android/
Мы делали так: управление все было в нативном коде, а для воспроизведения использовали родной java класс (MediaPlayer или как-то там) + обертка-прослойка. Из нативного кода вызывали методы обертки-прослойки, которая в себе содержала медиаплеер.
Ах да, мы остановились на формате .ogg потому что mp3 как-то плоховато работал :)
Если писать чисто на С++, то что лучше, OpenAL или OpenSL, где меньше долбаного кода пейсать? Я посмотрел примеры на хабре, и то, и то меня немного напугало.
TarasB
Не очень понятно про "долбаный код". Я 1 раз написал реализацию OpenSL ES по примерам, теперь только вызываю функции create_my_sound(), play_my_sound(), destroy_my_sound() (утрирую, конечно). А функции я реализовал и через OpenSL ES, и через OpenAL. Удобно для кроссплатформенности. Рекомендую.
P.S. Единственное, я как-то с ogg/vorbis не стал разбираться и тупо пользуюсь библиотеками libogg/libvorbis, хотя OpenSL ES вроде как сам умеет его декодировать...
Роман Шувалов
> Не очень понятно про "долбаный код"
Примеры с хабра немного не понравились, типа "создаёт интерфейс, не более 32 штук, как смешивать звуки хз то есть".
Пример из того, что шло в комплекте с НДК - там дохренища портянок с непроизносимыми названиями и с кучей жабовызовов внутри.
Роман Шувалов
> А функции я реализовал и через OpenSL ES, и через OpenAL.
На основе хабровского кода или того, что шло с НДК?
Роман Шувалов
> P.S. Единственное, я как-то с ogg/vorbis не стал разбираться и тупо пользуюсь
> библиотеками libogg/libvorbis, хотя OpenSL ES вроде как сам умеет его
> декодировать...
То есть ogg ты тоже пользуешься? А если надо одновременно много звуков, то что делаешь?
TarasB
> На основе хабровского кода или того, что шло с НДК?
Кажется с NDK. Не помню уже.
> То есть ogg ты тоже пользуешься?
Да, вручную его декодирую (libogg, libvorbis) и далее скармливаю OpenAL/OpenSLES.
> А если надо одновременно много звуков, то что делаешь?
Создаю несколько источников звука (sources для OpenAL, players для OpenSLES).
Читаю http://habrahabr.ru/post/176933/
постоянно продираюсь через опечатки, например, я полчаса потерял из-за того, что автор написал SL_TRUE вместо SL_BOOLEAN_TRUE, я долго не мог понять, почему компилятор не ест константу.
Очередной затык: автор использует переменную assetManager, абсолютно не объясняя, откуда она вообще взялась.
Также совершенно непонятно, чем по умолчанию надо инициализировать все эти engineObj, engine итд, я их инициализирую NULL, на свой страх и риск.
Вопрос: кто такой вообще этот взявшийся неожиданно и ниоткуда, как рояль в кустах, assetManaer?!
Походу у всех этот ассет берётся из внешнего жабакода, и примеры у них с элементами жабы. А без жабы это можно как-нибудь?
Так, я применил assetManager, который из state->activity->assetManager
закинул звук в архив, загрузил его:
AAsset *asset = AAssetManager_open(assetManager, "brick_shot.mp3", AASSET_MODE_UNKNOWN);
Файл с этим именем закинул в папку assets папки проекта.
Запускаю, звука нет, в логе ошибка
MPEG4Extractor E both mdat,ftyp not found OMXCodec D Try to create codec 'PB.LIBAV.AUDIO.DEC' OMXCodec D Try to create softwave codec PB.LIBAV.AUDIO.DEC AudoiTrack W obtainBuffer() track 0x2c8af0 disabled, restarting AudoiTrack W obtainBuffer() track 0x2c8af0 disabled, restarting AudoiTrack W obtainBuffer() track 0x2c8af0 disabled, restarting
Так-так-так.
Я заменил mp3 на ogg, и звук таки зазвучал! Видимо, просто в моём планшете не хватало нужного кодека.
Но новая проблема - звук издаётся лишь один раз...
void Sound::Play () { SLPlayItf player; SLresult result; result = ( *playerObj)->GetInterface( playerObj, SL_IID_PLAY, &player); if ( result != SL_RESULT_SUCCESS) tbal::LogW( "Error in GetInterface SL_IID_PLAY!"); SLSeekItf seek; result = ( *playerObj)->GetInterface( playerObj, SL_IID_SEEK, &seek); if ( result != SL_RESULT_SUCCESS) tbal::LogW( "Error in GetInterface SL_IID_SEEK!"); ( *seek)->SetLoop( seek, SL_BOOLEAN_FALSE, 0, SL_TIME_UNKNOWN); result = ( *player)->SetPlayState( player, SL_PLAYSTATE_PLAYING); if ( result != SL_RESULT_SUCCESS) tbal::LogW( "Error in SetPlayState!"); }
то есть этого недостаточно? Ааа, я должен переставить позицию в начало, да?
А, его надо останавливать перед тем, как запускать! Всё, заработало! Осталось только звуки записать, ложкой по чашке, ложкой по столу, ложкой по пластмасске, стеклом по стеклу, бульки в воде итд...
Тема в архиве.