06.Eclipse下Ndk開(kāi)發(fā)(使用fmod播放聲音)

(創(chuàng)建于2017/12/26)

1.搜索fmod,并下載代碼


5199906.png

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


5291234.png

5307203.png

我們首先使用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)為:


5667781.png

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


5845234.png

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

jni目錄:
5986921.png

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文件:


7252328.png

我們需要將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è)
8048718.png

說(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中


8567015.png

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


8624484.png

我們?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)行成功并且播放聲音了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容