美文网首页Android
JNI-NDK(Android NDK 导入 C库,开发流程)

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

作者: 大虾啊啊啊 | 来源:发表于2022-08-28 13:31 被阅读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"
    //        }
    
    • 关于cpu架构

      CPU架构模式:
      以前七个平台
      arm64-v8a 如果你现在去买 华为 小米
      armeabi-v7a 2015 小米4
      armeabi 2020 ~ 2011 就快没有了,越来越少了
      x86 x86_64 模拟器 ,WindowPhone

      如果知道自己手机的 CPU架构模式:
      adb shell getprop ro.product.cpu.abi
      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

    相关文章

      网友评论

        本文标题:JNI-NDK(Android NDK 导入 C库,开发流程)

        本文链接:https://www.haomeiwen.com/subject/odzqnrtx.html