Android

JNI-NDK(Android NDK 导入 C库,开发流程)

2022-08-28  本文已影响0人  大虾啊啊啊

Android NDK 导入 C库,开发流程,以导入fmod库为例,简单实现变声器效果


image.png

1、导入fmod

导入fmod头文件、so库、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库流程
#1、导入C库头文件 inc
include_directories("inc")

#2、配置总库,也就是最终打包到APK里的库
file(GLOB allCPP *.c *.h *.cpp)
add_library(
        native-lib # Sets the name of the library 给最终打包到APK的C库起名称 native-lib
        SHARED # Sets the library as a shared library.//设置库为动态共享库
        ${allCPP} # Provides a relative path to your source file(s).//导入所有源文件
)

#3、导入库文件 .so ,CMAKE_ANDROID_ARCH_ABI会自动匹配当前的CPU架构
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

#这种方式是一个个添加
#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、链接具体的库,到我们的 libnative-lib.so总库
target_link_libraries(
        native-lib
        #${log-varAAAA}
        log # 自动寻找  # 具体的库 链接到 libnative-lib.so里面去
        fmod # 具体的库 链接到 libnative-lib.so里面去
        fmodL # 具体的库 链接到 libnative-lib.so里面去
)

3、 配置gradle的cpu架构

        externalNativeBuild {
            cmake {
                 cppFlags "" // 默认五大平台

                // 指定CPU架构,Cmake的本地库, 例如:native-lib ---> armeabi-v7a
//                abiFilters "armeabi-v7a"
            }
        }
//
//        // 指定CPU架构,打入APK lib/CPU平台
//        ndk {
//            abiFilters "armeabi-v7a"
//        }

4、例子

以上环境配置完成,即可调用C库完成简单的变声器

(1)生成头文件

生成我们自己的头文件,并引入fmod的头文件,fmod.hpp。javah 包名即可生成头文件,并且会把Java中的常量对应生成C中的宏

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <fmod.hpp> // TODO 最后一步 FMOD的头文件,必须导入,才能使用功能
#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);
    //音效系统指针
    System *system = 0;
    //声音
    Sound *sound = 0;
    //通道
    Channel *channel = 0;
    //DSP:digital signal process  == 数字信号处理  指针
    DSP *dsp = 0;

    //创建系统
    System_Create(&system);
    //初始化最大音轨数
    system->init(32, FMOD_INIT_NORMAL, 0);
    //创建声音,传入路径 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、创建dsp
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //2、设置Pitch音调调节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、创建dsp
            system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);
            //2、设置Pitch音调调节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++调用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++回调java 播放完成
     *
     * @param msg
     */
    void playFinish(String msg) {
        Log.d(TAG, "playFinish: " + msg);
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

    /**
     * 调用native函数,播放声音
     *
     * @param playType
     */
    native void playNative(int playType, String path);
}

源码

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

上一篇下一篇

猜你喜欢

热点阅读