Android NDK的使用實(shí)例——fmod example

image

概述

這次記錄的是NDK的使用實(shí)例,使用 fmod 來(lái)處理變聲。有著上一次 Android NDK的使用實(shí)例——增量更新實(shí)戰(zhàn) 的實(shí)踐經(jīng)驗(yàn),一開(kāi)始還想著不會(huì)特別麻煩。實(shí)戰(zhàn)以后才發(fā)現(xiàn),連demo也不是簡(jiǎn)單導(dǎo)入就能夠跑起來(lái)的,為此也踩了不少坑。這次先記錄下如何成功跑起官方的demo。

fmod是什么?這是fmod的官網(wǎng) https://www.fmod.com。fmod是音效引擎游戲開(kāi)發(fā)革命引擎。很多著名游戲如魔獸都使用到該音效引擎,游戲開(kāi)發(fā)引擎Cocos2D、Unity3D更是直接內(nèi)置封裝了這個(gè)庫(kù)。正如Android也在Library層內(nèi)置封裝了OpenGL ES、SQLite等優(yōu)秀的庫(kù)。像fmod這種優(yōu)秀的C/C++庫(kù),有了NDK的支持,自然也可以應(yīng)用到Android應(yīng)用程序中,開(kāi)發(fā)類(lèi)似于QQ變聲等功能。

下載官方文件

官網(wǎng)注冊(cè)后,下載api解壓后打開(kāi),看到下圖所示。這里有一些文檔,其實(shí)我們只是想要跑Android的demo的話,只需要看到 api/lowlevel 低版本的api里面就能看我們熟悉的一些文件,比如 example/org.fmod.example/MainActivity、libfmod.so庫(kù)、fmod.jar包等。

image

如何使用

如何運(yùn)行這個(gè)demo?也查找了很多資料,看了很多文檔,而且這種問(wèn)題簡(jiǎn)單通俗的資料也不多。文末有參考博客。這里其實(shí)是運(yùn)行了一個(gè)播放聲音的demo,點(diǎn)擊不同的按鈕就播放不同的聲音。UI操作如下:

image

新建一個(gè)C++ support工程,這里還是使用CMake的方式。既然這里要使用的功能就是播放聲音,看下載的文件發(fā)現(xiàn)有個(gè) play_sound.cpp 的類(lèi),copy進(jìn)來(lái),編譯,隨之發(fā)現(xiàn)引用到的其他幾個(gè)頭文件、源文件也是需要一起copy進(jìn)來(lái)。最終的軟件工程目錄是這樣的。

image

需要注意的地方

1、添加權(quán)限
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2、修改 include 路徑

因?yàn)槲覀冎苯觕opy了整個(gè) inc 文件夾,有幾個(gè)文件 play_sound.cpp、common.cpp、common.h 就需要修改 include 的路徑了

#include "inc/fmod.hpp"
#include "inc/fmod_errors.h"
3、修改JNI方法定義

這里的MainActivity的包名最好保證是 org.fmod.example,要么就到
common_platform.cpp 里面修改相應(yīng)的方法名,按照J(rèn)NI的命名規(guī)范。

extern "C"
{

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_main(JNIEnv *env, jobject thiz)
{
    gJNIEnv = env;
    gMainActivityObject = thiz;

    FMOD_Main();
}

} /* extern "C" */

預(yù)編譯so庫(kù)

修改 CMakeLists.txt,這個(gè)才是這次記錄的重點(diǎn)。因?yàn)閒mod的很多源代碼并沒(méi)有全部開(kāi)源出來(lái),很多都是以so庫(kù)的形式存在fmod.so、fmodL.so里面,因此,我們需要預(yù)編譯這些so庫(kù),不然無(wú)法編譯通過(guò)。

# 設(shè)置構(gòu)建這個(gè)so庫(kù)所需要的最小CMake版本
cmake_minimum_required(VERSION 3.4.1)

# 設(shè)置一個(gè)變量path_project,后面預(yù)編譯so庫(kù)的時(shí)候會(huì)使用到
set(path_project /document/workandroid/NdkTest6_fmod)

# 添加默認(rèn)需要生成的so庫(kù)
add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             # 這里最好把相關(guān)的cpp源文件都添加進(jìn)來(lái)
             src/main/cpp/play_sound.cpp
             src/main/cpp/common.cpp
             src/main/cpp/common_platform.cpp
             src/main/cpp/native-lib.cpp )

# 注意:這里添加兩個(gè)需要預(yù)編譯的so庫(kù)fmod.so、fmodL.so,也就是上面的cpp源文件的部分源代碼
# 是在so庫(kù)里面,并沒(méi)有全部開(kāi)源出來(lái),我們要先預(yù)編譯so庫(kù),才能編譯通過(guò)
add_library(
    fmod
    SHARED
    IMPORTED )

# 設(shè)置預(yù)編譯的so庫(kù)的路徑,這里要使用絕對(duì)路徑,不然會(huì)鏈接錯(cuò)誤,
# 測(cè)試了使用相對(duì)路徑編譯通過(guò),但運(yùn)行崩潰。
set_target_properties(
    fmod
    PROPERTIES IMPORTED_LOCATION
    ${path_project}/app/src/main/jniLibs/${ANDROID_ABI}/libfmod.so )

add_library(
    fmodL
    SHARED
    IMPORTED )
set_target_properties(
    fmodL
    PROPERTIES IMPORTED_LOCATION
    ${path_project}/app/src/main/jniLibs/${ANDROID_ABI}/libfmodL.so )

# 找到Android內(nèi)置的log庫(kù),用于打印log
find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# 這里需要把預(yù)編譯的so庫(kù),鏈接到默認(rèn)生成的native-lib.so庫(kù)中
# 后續(xù)System.loadLibrary("native-lib")就可以包含預(yù)編譯的so庫(kù)了。
target_link_libraries( # Specifies the target library.
                       native-lib
                       fmod
                       fmodL

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

注意:在MainActivity中只需要

System.loadLibrary("native-lib");

就可以,因?yàn)樵?CMakeLists.txt 已經(jīng)將預(yù)編譯的fmod.so、fmodL.so鏈接到該so庫(kù)中了。
構(gòu)建通過(guò),運(yùn)行demo。

總結(jié)

這里再理一下整個(gè)過(guò)程。首先要知道的是,這個(gè)demo提供的是一個(gè)播放聲音方法。所以需要引入 play_sound.cpp,以及相對(duì)應(yīng)的其他cpp文件、jar包。然后需要將這些文件構(gòu)建成so庫(kù),而構(gòu)建這個(gè)so庫(kù)要需要其他的so庫(kù)fmod.so、fmodL.so,這就是涉及到CMake的使用,如何預(yù)編譯其他依賴(lài)的so庫(kù)。將相關(guān)的so庫(kù),頭文件,源文件都準(zhǔn)備好之后,通過(guò)CMake構(gòu)建腳本,就可以構(gòu)建出目標(biāo)的so庫(kù) native-lib.so,然后就可以執(zhí)行播放聲音了。

下一次將要使用這個(gè)庫(kù)來(lái)制作變聲效果。

Demo代碼已上傳至我的 GitHub

感謝

FMOD
Android NDK開(kāi)發(fā)之旅25--NDK--模仿QQ變聲特效
Android Studio NDK開(kāi)發(fā)(九):變聲特效

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容