Проигрываем музыку с помощью fmod
FMOD — проприетарная программная аудио библиотека, которая позволяет проигрывать музыкальные файлы различных форматов. Эта библиотека написана на С++ и используется во многих известных играх, например Call of Duty 4 Diablo 3 Far Cry, Bioshock и др… У меня возникла необходимость в ее использовании в Android и после долгих поисков как это сделать я решил написать статью. Для начала нужно скачать саму библиотеку FMOD Ex под андроид http://www.fmod.org/fmod-downloads.html. Там содержится документация и все необходимые файлы. Далее нужно настроить android ndk. Он нужен для того, чтобы можно было запускать код C/C++ в андроид проекте http://developer.android.com/tools/sdk/ndk/index.html. У меня Mac OS поэтому качал версию под Mac OS X 32-bit. После того когда ndk скачано нужно настроить Eclipse для поддержки Android ndk и заставить проект работать с C/C++ кодом. Шаг 1: Настраиваем среду Итак, создаем новый проект (playSound). Я выбирал под андроид 2.3, после чего нужно указать где находится ndk (Eclipse -> Preferences -> Android -> NDK) и в NDK Location указать путь к скачанному ndk.
Когда путь к ndk указан, нужно добавить в проект поддержку ndk. Для этого щелкаем правой клавишей на проекте -> Android Tools -> Add Native Support…
Далее нужно указать имя файла который будет создаваться. Это будет сишний файл, в котором мы будем писать сишный код или вызывать функции из других сишных файлов или библиотек. На этапе компиляции программы будет создана библиотека, которая будет называться так же как и файл и работа с сишным кодом будет именно с помощью этой библиотеки.
Если же нажать на Finish то в проекте появляется папка jni (Java Native Interface) в которой появилось 2 файла (PlaySound.cpp и Android.mk).
В Android.mk содержатся настройки для сборки библиотеки. Там мы должны указать все файлы, которые будут принимать участие в создании библиотеки. Сейчас он выглядит так:
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE := PlaySound LOCAL_SRC_FILES := PlaySound.cpp
LOCAL_MODULE название библиотеки которая сформируется LOCAL_SRC_FILES название файлов, которые принимают участие в формировании библиотеки.
Если сейчас сделать билд проекта (command + B), то в папке libs появилась папка armabi и в ней находится библиотека libPlaySound.so. На данный момент она не содержит никаких функций или методов, но если их описать и делать их вызов с java кода, то вызываться они будут как раз из этой библиотеки. Эта библиотека сформировалась из файла (PlaySound.cpp). Для того чтобы использовать функции из fmod, нам нужно подключить готовую библиотеку libfmod.so которая скачана с сайта fmod. Если ее скопировать в папку armabi то она там не появится, так как эта папка создается на этапе компиляции и библиотеки туда добавляются динамически. Для включения звукового выхода через режим звуковой дорожки необходимо включить и инициализировать Java FMOD аудио драйвер в приложении (не обязательно, если используется OpenSL выход). Для этого необходимо будет добавить fmodex.jar в проект Java, и импортировать org.fmod.FMODAudioDevice пакет. Аудио Драйвер Java FMOD также требует, чтобы приложение загружало fmodex библиотеку.
FMODAudioDevice класс имеет две функции которые необходимо вызвать для проигрывания аудио. Они могут быть вызваны в любое время, но в документации рекомендуется делать вызовы start() и stop() в переопределеннsые методы onStart() и onStop ().
fmodex.jar находится в архиве который скачан с сайта fmod. fmodapi44418android -> api -> lib -> fmodex.jar
Для того чтобы добавить jar файл в проект нужно скопировать его в папку libs. В eclipse достаточно перетащить ее туда с помощью мышки и подтвердить копирование.
Теперь нужно добавить эту библиотеку в Java Build Path. Для этого нужно нажать правой клавишей по проекту и зайти в свойства проекта.
Далее переход в вкладку Java Build Path, а там в вкладку Libraries и нажимаем Add jars… Там нужно указать где находится fmodex.jar в проекте и жмем ОК.
и дале переход в вкладку Order and Export и поставить галочку на только что добавленой библиотеке.
Нажимаем Ок и можем приступать к инициализации аудио драйвера. Переходим в MainActivity.java и добавляем два Override методы.
import android.os.Bundle; import android.app.Activity;
public class MainActivity extends Activity
FMODAudioDevice использует функции, которые находятся в сишной библиотеке libfmodex.so. Если сейчас запустить проект, то будет ошибка, потому что компилятор не сможет найти этой библиотеки. static
В этом месте указано что библиотека fmodex будет загружаться в проект. Остается ее разместить в папке libs -> armabi. Для этого я из папки fmodapi44418android копирую папку api в рабочую папку, где лежит мой проект
И в Android.mk указываю путь к библиотекам.
LOCAL_PATH := $(call my-dir)
# # FMOD Ex Shared Library # include $(CLEAR_VARS)
LOCAL_MODULE := fmodex LOCAL_SRC_FILES := ../../api/lib/$(TARGET_ARCH_ABI)/libfmodex.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../api/inc
LOCAL_SRC_FILES – путь к библиотекам LOCAL_EXPORT_C_INCLUDES – путь к заголовочным файлам
Также обязательно нужно указать, что библиотека fmodex будет подключаться и использоваться в созданной библиотеке PlaySound. so include $(CLEAR_VARS)
LOCAL_MODULE := PlaySound LOCAL_SRC_FILES := PlaySound.cpp LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := fmodex
LOCAL_LDLIBS := -llog для того чтобы можно было пользоваться LogCat в сишных модулях.
Полный код файла выглядит так:
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE := PlaySound LOCAL_SRC_FILES := PlaySound.cpp LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := fmodex
# # FMOD Ex Shared Library # include $(CLEAR_VARS)
LOCAL_MODULE := fmodex LOCAL_SRC_FILES := ../../api/lib/$(TARGET_ARCH_ABI)/libfmodex.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../api/inc
Когда пути добавлены, нужно сделать build проекта (command + B) и в папке armabi появляется необходимая библиотека
Теперь можем запускать проект и убедиться что программа успешно выполнилась и библиотеки все проинициализированы.
Шаг 2. Проигрываем музыку Поскольку libfmodex сишная библиотека, то и пользоваться ею нужно с сишного кода, а вызывать его в java коде. Для этого в java надо написать какую функцию реализовать в сишном коде. Override protected void onCreate(Bundle savedInstanceState)
public native void play(String path); Теперь нужно реализовать функцию play в PlaySound.cpp. Можно писать самому, а можно воспользоваться утилитой javah. Для этого нужно открыть терминал, перейти в директорию с проектом и вызвать javah. У меня это выглядело так:
com.example.playsound — название пакета, а MainActivity — класс где находится описание функции которую нужно сгенерировать.
После обновления проекта (F5) видно что появился новый файл com_example_playsound_MainActivity.h
Он содержит прототип функции play, который выглядит так:
JNIEXPORT void JNICALL Java_com_example_playsound_MainActivity_play (JNIEnv *, jobject, jstring);
Переходим в PlaySound.cpp и добавляем необходимые нам библиотеки для работы с fmod.
#include "../../api/inc/fmod_errors.h" #include "../../api/inc/fmod.h"
Ну и конечно все остальные при необходимости. Также я еще подключил
#include <android/log.h> #include <stdlib.h> #include <string.h>
Для того чтобы можно было выводить сообщения в LogCat, работать со строками и др. И конечно файл с прототипом функции play. #include «com_example_playsound_MainActivity.h»
Далее реализуем функцию:
#include <jni.h> #include <android/log.h> #include <stdlib.h> #include <string.h> #include «com_example_playsound_MainActivity.h» #include "../../api/inc/fmod_errors.h" #include "../../api/inc/fmod.h"
JNIEXPORT void JNICALL Java_com_example_playsound_MainActivity_play (JNIEnv *env, jobject thiz, jstring mediaPath)
GetStringUTFChars(mediaPath, NULL);// Создаем необходимые переменные FMOD_SYSTEM *gSystem; FMOD_SOUND *sound; FMOD_CHANNEL *channel; FMOD_RESULT result = FMOD_OK;
// Инициализируем среду fmod. FMOD_System_Create(&gSystem); result = FMOD_System_Init(gSystem, 32, FMOD_INIT_NORMAL, 0); if (result != FMOD_OK) // если возникла ошибка, то выводим ее в LogCat __android_log_print(ANDROID_LOG_ERROR, «fmod», «FMOD error! (%d) %s\n%s:%d», result, FMOD_ErrorString(result), __FILE__, __LINE__);
// Создаем песню и проигрываем FMOD_System_CreateSound(gSystem, _mediaPath, FMOD_DEFAULT, 0, &sound); FMOD_System_PlaySound(gSystem, FMOD_CHANNEL_FREE, sound, false, &channel); >
Теперь осталось добавить в MainActivity загрузку библиотеки PlaySound static
записать на устройство свою любимую песенку, получить путь к ней и вызвать play.
Песню я записал в корень карты памяти.
Override protected void onCreate(Bundle savedInstanceState)
Проблема только в том, что нужно долго ждать чтобы песня проигралась (на моем дешевом китайском где-то около минуты ).