(創(chuàng)建于2017/12/26)
1.搜索fmod,并下載代碼

2.拿到Android相關(guān)的代碼后,打開(kāi)目錄結(jié)構(gòu)


我們首先使用lowlevel中的代碼先將程序運(yùn)行起來(lái),后續(xù)實(shí)現(xiàn)變聲功能
3.創(chuàng)建eclipse中的安卓項(xiàng)目,將jar包fmod.jar拷貝到libs文件夾下并添加到build path
4.創(chuàng)建jni目錄(eclipse項(xiàng)目根目錄),將下載代碼中的so庫(kù)拷貝到j(luò)ni目錄,以armeabi中的一個(gè)為例,然后將inc中的頭文件全部拷貝到j(luò)ni目錄下,
本次只實(shí)現(xiàn)播放聲音,所以我們拷貝example中的play_sound.cpp文件到j(luò)ni目錄下,此時(shí)目錄結(jié)構(gòu)為:

5.點(diǎn)擊進(jìn)入play_sound.cpp,看到兩個(gè)頭文件:

fmod在inc目錄下,需要加上路徑,common.h還沒(méi)有引入,所以我們拷貝common.h到j(luò)ni目錄下

jni目錄:

6.點(diǎn)擊進(jìn)入common.h中,發(fā)現(xiàn)它還引用了common_platform.h 頭文件,所以拷貝common_platform到j(luò)ni目錄下,(拷貝頭文件的時(shí)候,將相應(yīng)的cpp文件也拷貝進(jìn)來(lái),常識(shí)),修改不正確的頭文件路徑,每個(gè)新引入的頭文件或者源文件,都要首先檢查它引入的其他的頭文件或源文件的引入路徑是否正確,不正確的做修改
7.將example中的MainActivity拷貝到我們項(xiàng)目中并覆蓋,修改類中報(bào)錯(cuò)的地方,發(fā)現(xiàn)一段關(guān)鍵代碼:
org.fmod.FMOD.init(this);
可以猜想,這段代碼就是jar包中的,解壓查看可以證實(shí)
往下可以看到加載動(dòng)態(tài)庫(kù)的代碼:
static
{
/*
* To simplify our examples we try to load all possible FMOD
* libraries, the Android.mk will copy in the correct ones
* for each example. For real products you would just load
* 'fmod' and if you use the FMOD Studio tool you would also
* load 'fmodstudio'.
*/
// Try debug libraries...
try { System.loadLibrary("fmodD");
System.loadLibrary("fmodstudioD"); }
catch (UnsatisfiedLinkError e) { }
// Try logging libraries...
try { System.loadLibrary("fmodL");
System.loadLibrary("fmodstudioL"); }
catch (UnsatisfiedLinkError e) { }
// Try release libraries...
try { System.loadLibrary("fmod");
System.loadLibrary("fmodstudio"); }
catch (UnsatisfiedLinkError e) { }
System.loadLibrary("stlport_shared");
System.loadLibrary("example");
}
目前我們就只是引入了libfmod.so和libfmodL.so,所以,多余的可以去掉,得到結(jié)果:
static
{
/*
* To simplify our examples we try to load all possible FMOD
* libraries, the Android.mk will copy in the correct ones
* for each example. For real products you would just load
* 'fmod' and if you use the FMOD Studio tool you would also
* load 'fmodstudio'.
*/
try {
System.loadLibrary("fmodL");
}
catch (UnsatisfiedLinkError e) { }
try {
System.loadLibrary("fmod");
}
catch (UnsatisfiedLinkError e) { }
//我們自己的添加本地支持時(shí)生成的so名字
System.loadLibrary("qq_voice");
}
再往下可以看到一系列的native方法,有native方法,就必然有cpp文件中有對(duì)應(yīng)的jni方法,所以我們需要將包名改成正確的,這里
簡(jiǎn)單粗暴一點(diǎn),直接將項(xiàng)目包名改成jni方法中的包名,這樣就不必修改cpp和頭文件中的代碼了
private native String getButtonLabel(int index);
private native void buttonDown(int index);
private native void buttonUp(int index);
private native void setStateCreate();
private native void setStateStart();
private native void setStateStop();
private native void setStateDestroy();
private native void main();
對(duì)應(yīng)的jni方法位于common_platform.cpp中:
jstring Java_org_fmod_example_MainActivity_getButtonLabel(JNIEnv *env, jobject thiz, jint index)
{
return env->NewStringUTF(Common_BtnStr((Common_Button)index));
}
void Java_org_fmod_example_MainActivity_buttonDown(JNIEnv *env, jobject thiz, jint index)
{
gDownButtons |= (1 << index);
}
void Java_org_fmod_example_MainActivity_buttonUp(JNIEnv *env, jobject thiz, jint index)
{
gDownButtons &= ~(1 << index);
}
void Java_org_fmod_example_MainActivity_setStateCreate(JNIEnv *env, jobject thiz)
{
}
void Java_org_fmod_example_MainActivity_setStateStart(JNIEnv *env, jobject thiz)
{
gSuspendState = false;
}
void Java_org_fmod_example_MainActivity_setStateStop(JNIEnv *env, jobject thiz)
{
gSuspendState = true;
}
void Java_org_fmod_example_MainActivity_setStateDestroy(JNIEnv *env, jobject thiz)
{
gQuitState = true;
}
void Java_org_fmod_example_MainActivity_main(JNIEnv *env, jobject thiz)
{
gJNIEnv = env;
gMainActivityObject = thiz;
FMOD_Main();
}
7.文件拷貝差不多了,我們就添加native支持,右鍵->Android tools ->add native support,設(shè)置so文件名,打開(kāi)Android.mk文件:

我們需要將LOCAL_SRC_FILES := qq_voice2.cpp
改成
LOCAL_SRC_FILES :=play_sound.cpp
build project一下,發(fā)現(xiàn)報(bào)錯(cuò),從第一個(gè)錯(cuò)誤開(kāi)始
jni/play_sound.cpp:23: error: undefined reference to 'Common_Init(void**)'
Common_Init 是common_platform.cpp中的方法,但是卻提示找不到,是因?yàn)槲覀兊腁ndroid.mk文件中沒(méi)有配置編譯,它需要和
play_sound.cpp一同編譯才行,因?yàn)閜lay_sound依賴common_platform
修改之前:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := qq_voice2
LOCAL_SRC_FILES := play_sound.cpp
include $(BUILD_SHARED_LIBRARY)
修改添加之后:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := qq_voice2
LOCAL_SRC_FILES := play_sound.cpp common_platform.cpp
include $(BUILD_SHARED_LIBRARY)
build一下,common_platform.cpp仍然報(bào)錯(cuò),是因?yàn)檫@兩個(gè)
說(shuō)明它使用了STL,標(biāo)準(zhǔn)模板庫(kù)
需要在Application.mk中設(shè)置支持
##支持C++異常處理,標(biāo)準(zhǔn)莫板塊
APP_STL := gnustl_static
build之后,不在爆紅
然后解決這個(gè)問(wèn)題
jni/play_sound.cpp:29: error: undefined reference to 'ERRCHECK_fn(FMOD_RESULT, char const*, int)'
異常處理,需要引入[common.cpp](file://C:\gaoyuan\code\workspace-android\qq_voice2\jni\common.cpp)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := qq_voice2
LOCAL_SRC_FILES := play_sound.cpp common_platform.cpp common.cpp
include $(BUILD_SHARED_LIBRARY)
在Android.mk中添加預(yù)編譯的兩個(gè)so文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fmod
LOCAL_SRC_FILES := libfmod.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := fmodL
LOCAL_SRC_FILES := libfmodL.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := qq_voice2
LOCAL_SRC_FILES := play_sound.cpp common_platform.cpp common.cpp
LOCAL_SHARED_LIBRARIES := fmod fmodL
include $(BUILD_SHARED_LIBRARY)
在build,編譯已經(jīng)成功了,但是運(yùn)行崩潰,是因?yàn)樾枰囊纛l文件沒(méi)有導(dǎo)入,可以看play_sound中

這三個(gè)文件需要導(dǎo)入,點(diǎn)擊Common_MediaPath可以看到這些文件放入assets目錄下即可

我們?cè)谙螺d的代碼中的media文件夾下找到這三個(gè)并拷貝進(jìn)來(lái),運(yùn)行發(fā)現(xiàn)報(bào)錯(cuò),原來(lái)是加載動(dòng)態(tài)庫(kù)的時(shí)候,
//我添加本地支持時(shí)生成的so名字
System.loadLibrary("qq_voice");這樣寫(xiě)的,而實(shí)際上生成的so是qq_void2所以導(dǎo)致加載不到,修改即可
System.loadLibrary("qq_voice2")
到此,已經(jīng)可以運(yùn)行成功并且播放聲音了