JNI-NDK(Android NDK 導(dǎo)入 C庫(kù)蛉鹿,開發(fā)流程)

Android NDK 導(dǎo)入 C庫(kù)滨砍,開發(fā)流程,以導(dǎo)入fmod庫(kù)為例妖异,簡(jiǎn)單實(shí)現(xiàn)變聲器效果


image.png

1惋戏、導(dǎo)入fmod

導(dǎo)入fmod頭文件、so庫(kù)他膳、jar


image.png

2响逢、配置Cmake文件

#cmake_minimum_required(VERSION 3.4.1) # 最低支持Cmake版本

cmake_minimum_required(VERSION 3.10.2)# 最低支持Cmake版本
# Declares and names the project.
project("jni_02")

#NDK集成C庫(kù)流程
#1、導(dǎo)入C庫(kù)頭文件 inc
include_directories("inc")

#2棕孙、配置總庫(kù)舔亭,也就是最終打包到APK里的庫(kù)
file(GLOB allCPP *.c *.h *.cpp)
add_library(
        native-lib # Sets the name of the library 給最終打包到APK的C庫(kù)起名稱 native-lib
        SHARED # Sets the library as a shared library.//設(shè)置庫(kù)為動(dòng)態(tài)共享庫(kù)
        ${allCPP} # Provides a relative path to your source file(s).//導(dǎo)入所有源文件
)

#3、導(dǎo)入庫(kù)文件 .so ,CMAKE_ANDROID_ARCH_ABI會(huì)自動(dòng)匹配當(dāng)前的CPU架構(gòu)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

#這種方式是一個(gè)個(gè)添加
#add_library( # Sets the name of the library.
#        jni_01
#        # Sets the library as a shared library.
#        SHARED
#        # Provides a relative path to your source file(s).
#        native-lib.cpp extern-lib.cpp)

#4蟀俊、鏈接具體的庫(kù)钦铺,到我們的 libnative-lib.so總庫(kù)
target_link_libraries(
        native-lib
        #${log-varAAAA}
        log # 自動(dòng)尋找  # 具體的庫(kù) 鏈接到 libnative-lib.so里面去
        fmod # 具體的庫(kù) 鏈接到 libnative-lib.so里面去
        fmodL # 具體的庫(kù) 鏈接到 libnative-lib.so里面去
)

3、 配置gradle的cpu架構(gòu)

        externalNativeBuild {
            cmake {
                 cppFlags "" // 默認(rèn)五大平臺(tái)

                // 指定CPU架構(gòu)肢预,Cmake的本地庫(kù)矛洞, 例如:native-lib ---> armeabi-v7a
//                abiFilters "armeabi-v7a"
            }
        }
//
//        // 指定CPU架構(gòu),打入APK lib/CPU平臺(tái)
//        ndk {
//            abiFilters "armeabi-v7a"
//        }
  • 關(guān)于cpu架構(gòu)

    CPU架構(gòu)模式:
    以前七個(gè)平臺(tái)
    arm64-v8a 如果你現(xiàn)在去買 華為 小米
    armeabi-v7a 2015 小米4
    armeabi 2020 ~ 2011 就快沒有了烫映,越來越少了
    x86 x86_64 模擬器 沼本,WindowPhone

    如果知道自己手機(jī)的 CPU架構(gòu)模式:
    adb shell getprop ro.product.cpu.abi
    armeabi-v7a

4、例子

以上環(huán)境配置完成锭沟,即可調(diào)用C庫(kù)完成簡(jiǎn)單的變聲器

(1)生成頭文件

生成我們自己的頭文件抽兆,并引入fmod的頭文件,fmod.hpp族淮。javah 包名即可生成頭文件辫红,并且會(huì)把Java中的常量對(duì)應(yīng)生成C中的宏

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <fmod.hpp> // TODO 最后一步 FMOD的頭文件,必須導(dǎo)入瞧筛,才能使用功能
#include <string>
/* Header for class com_it_jni_02_MainActivity */

#ifndef _Included_com_it_jni_02_MainActivity
#define _Included_com_it_jni_02_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_it_jni_02_MainActivity_MODE_LUOLI
#define com_it_jni_02_MainActivity_MODE_LUOLI 1L
#undef com_it_jni_02_MainActivity_MODE_DASHU
#define com_it_jni_02_MainActivity_MODE_DASHU 2L
/*
 * Class:     com_it_jni_02_MainActivity
 * Method:    playNative
 * Signature: (I)V
 */
JNIEXPORT void JNICALL
Java_com_it_jni_102_MainActivity_playNative
(JNIEnv
*, jobject, jint,jstring);

#ifdef __cplusplus
}
#endif
#endif

(2)編寫cpp代碼
#include <jni.h>
#include <string>
#include <unistd.h>
#include "com_it_jni_02_MainActivity.h"

using namespace FMOD; // fmod的命名空間
extern "C"
JNIEXPORT void JNICALL
/**
 *
 * @param env
 * @param thiz
 * @param playType  播放類型
 * @param path  播放路徑
 */
Java_com_it_jni_102_MainActivity_playNative(JNIEnv *env, jobject thiz, jint playType,
                                            jstring path) {
    char *content = "播放完畢啦";
    //播放路徑
    const char *playPath = env->GetStringUTFChars(path, NULL);
    //音效系統(tǒng)指針
    System *system = 0;
    //聲音
    Sound *sound = 0;
    //通道
    Channel *channel = 0;
    //DSP:digital signal process  == 數(shù)字信號(hào)處理  指針
    DSP *dsp = 0;

    //創(chuàng)建系統(tǒng)
    System_Create(&system);
    //初始化最大音軌數(shù)
    system->init(32, FMOD_INIT_NORMAL, 0);
    //創(chuàng)建聲音,傳入路徑 playPath
    system->createSound(playPath, FMOD_DEFAULT, 0, &sound);
    //播放聲音
    system->playSound(sound, 0, false, &channel);


    switch (playType) {
        //蘿莉聲音
        case com_it_jni_02_MainActivity_MODE_LUOLI:
            //1厉熟、創(chuàng)建dsp
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //2、設(shè)置Pitch音調(diào)調(diào)節(jié)2.0
            dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 2.0f);
            //3较幌、添加音效到音軌
            channel->addDSP(0, dsp);
            content = "蘿莉播放完成";
            break;
            //大叔聲音
        case com_it_jni_02_MainActivity_MODE_DASHU:
            //1揍瑟、創(chuàng)建dsp
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //2、設(shè)置Pitch音調(diào)調(diào)節(jié)2.0
            dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.5f);
            //3乍炉、添加音效到音軌
            channel->addDSP(0, dsp);
            content = "大叔播放完成";
            break;

    }
    bool isPlaying = true;
    //等待播放完畢
    while (isPlaying) {
        channel->isPlaying(&isPlaying);
        usleep(1000 * 1000);
    }
    //JNI中使用 記得回收
    sound->release();
    system->close();
    system->release();
    env->ReleaseStringUTFChars(path, playPath);
    //C++調(diào)用Java 通知播放完成
    //獲取jclass
    jclass j_class = env->GetObjectClass(thiz);
    jmethodID jmethod_Id = env->GetMethodID(j_class, "playFinish", "(Ljava/lang/String;)V");
    jstring j_string = env->NewStringUTF(content);
    env->CallVoidMethod(thiz, jmethod_Id, j_string);


}
(3)編寫Java代碼
package com.it.jni_02;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.it.jni_02.databinding.ActivityMainBinding;

import org.fmod.FMOD;

public class MainActivity extends AppCompatActivity {
    //蘿莉聲音
    private static final int MODE_LUOLI = 1; //
    //大叔聲音
    private static final int MODE_DASHU = 2; //

    private static final String path = "file:///android_asset/daxiaa.m4a";
    private static final String TAG = "MainActivity";

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        FMOD.init(this);
        binding.btnLuoli.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                playNative(MODE_LUOLI, path);
            }
        });
        binding.btnDashu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                playNative(MODE_DASHU, path);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        FMOD.close();
    }

    /**
     * c++回調(diào)java 播放完成
     *
     * @param msg
     */
    void playFinish(String msg) {
        Log.d(TAG, "playFinish: " + msg);
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

    /**
     * 調(diào)用native函數(shù)绢片,播放聲音
     *
     * @param playType
     */
    native void playNative(int playType, String path);
}

源碼

https://gitee.com/daxiaa/jni-ndk.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滤馍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子底循,更是在濱河造成了極大的恐慌巢株,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熙涤,死亡現(xiàn)場(chǎng)離奇詭異阁苞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祠挫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門那槽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人等舔,你說我怎么就攤上這事骚灸。” “怎么了慌植?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵甚牲,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我蝶柿,道長(zhǎng)丈钙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任只锭,我火速辦了婚禮著恩,結(jié)果婚禮上院尔,老公的妹妹穿的比我還像新娘蜻展。我一直安慰自己,他們只是感情好邀摆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布纵顾。 她就那樣靜靜地躺著,像睡著了一般栋盹。 火紅的嫁衣襯著肌膚如雪施逾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天例获,我揣著相機(jī)與錄音汉额,去河邊找鬼。 笑死榨汤,一個(gè)胖子當(dāng)著我的面吹牛蠕搜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播收壕,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妓灌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼轨蛤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起虫埂,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤祥山,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掉伏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缝呕,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年斧散,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了岳颇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颅湘,死狀恐怖话侧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闯参,我是刑警寧澤瞻鹏,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站鹿寨,受9級(jí)特大地震影響新博,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜脚草,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一赫悄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧馏慨,春花似錦埂淮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至慕趴,卻和暖如春痪蝇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冕房。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工躏啰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耙册。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓给僵,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親觅玻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子想际,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

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