Android NDK 導(dǎo)入 C庫(kù)滨砍,開發(fā)流程,以導(dǎo)入fmod庫(kù)為例妖异,簡(jiǎn)單實(shí)現(xiàn)變聲器效果
1惋戏、導(dǎo)入fmod
導(dǎo)入fmod頭文件、so庫(kù)他膳、jar
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);
}