阿里巴巴语音识别----安卓APK本地部署教程 funasr安卓部署
讲述一下部署安卓APK的过程:参考fawai-asr的github代码完成的!主要就是写了CMakeLists.txt的信息,找到onnxruntime-android和FFmpeg-android的.so文件供给安卓app去调用。
主要就是三个文件去生成想要的东西! GITHUB地址:https://github.com/jianyangshi/funasr-android
需要生成的ffmpeg.so 这里的SO需要给安卓调用,只需要从github上去下载源码生成即可!安卓的SO包都有,所以不需要自己编译!
编译build_androidv8.sh 可以直接复制下面的代码进去
#!/bin/bash
NDK=/home/sjy/Android/android-ndk-r26b
HOST_TAG=linux-x86_64
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
#ANDROID_LIB_PATH="$(pwd)/android"
ARCH=arm64
CPU=armv8-a
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
PREFIX=$(pwd)/android/$CPU
CROSS_PREFIX=$TOOLCHAIN/bin/llvm-
#OPTIMIZE_CFLAGS="-march=$ARCH"
API=29
BASEPATH=$(cd `dirname $0`; pwd)
echo $BASEPATH
NM=$TOOLCHAIN/bin/llvm-nm
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
#FDK_INCLUDE=$BASEPATH/fdk-aac/android/$CPU/include
echo $CC
echo $CXX
function build_android_arm
{
echo "build ffmpeg for android $CPU"
./configure \
--prefix=$PREFIX \
--disable-gpl \
--disable-postproc \
--enable-shared \
--enable-jni \
--enable-neon \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--disable-stripping \
--extra-cflags="-Os -fpic -mfpu=neon -mfloat-abi=softfp -marm" \
--enable-nonfree \
--enable-gpl \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--nm=$NM \
--cc=$CC \
--cxx=$CXX \
--sysroot=$SYSROOT
#make clean
#make -j2
#make install
echo "configure ffmpeg for android $CPU completed"
}
export AR=$TOOLCHAIN/bin/llvm-ar
export AS=$TOOLCHAIN/bin/llvm-as
export LD=$TOOLCHAIN/bin/llvm-ld
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip
build_android_arm
#make clean
#make && make install
等待生成文件夹下面的ANDROID即可。把ANDROID的文件夹放到CMakeLists.txt里面的FFMPEG_DIR即可。
可以参照一些博客的参数介绍
编译FAWASR-SJY目录下的asr_engine/androidlib/build-android.sh CMakeLists.txt fawasr2pass.cc 编辑这三个文件先!
# build-android.sh
dir=$PWD/build
mkdir -p $dir
cd $dir
# -DFFMPEG_DIR=/home/sjy/ffmpeg-master-latest-armv8-gpl-shared \
cmake -DCMAKE_BUILD_TYPE=release \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_TOOLCHAIN_FILE="/home/sjy/Android/Sdk/ndk/25.1.8937393/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="arm64-v8a" \
-DANDROID_PLATFORM="android-26" \
-DCMAKE_INSTALL_PREFIX=./install ..
make -j4
// fawasr2pass.cc 你可以选择搞什么模式下的安卓JNI调用
#include "jni.h"
#include "precomp.h"
#ifdef __cplusplus
namespace funasroff {
FUNASR_HANDLE tpass_handle = nullptr;
FUNASR_HANDLE tpass_online_handle = nullptr;
// FUNASR_RESULT FunTpassInferBuffer = nullptr;
FUNASR_RESULT result = nullptr;
FUNASR_DEC_HANDLE decoder_handle = nullptr;
std::string vad_sub_dir = "/vad_res";
std::string asr_offline_sub_dir = "/asr_offline_res";
std::string asr_online_sub_dir = "/asr_online_res";
std::string punc_sub_dir = "/punc_res";
std::string online_res = "";
std::string tpass_res = "";
std::string nn_hotwords_ = "";
std::string hotword = "/hotword";
std::vector<std::vector<float>> hotwords_embedding = CompileHotwordEmbedding(tpass_handle, nn_hotwords_, ASR_TWO_PASS);
std::string offline_res = "";
std::vector<std::vector<std::string>> punc_cache(2);
int thread_num = 1;
extern "C"
JNIEXPORT void JNICALL Java_com_fawai_asr_OnnxInter_ASRInitOffline(
JNIEnv *env, jobject /*obj*/, jstring jModelDir)
{
const char* pModelDir = env->GetStringUTFChars(jModelDir, nullptr);
std::cout << "pModelDir" << pModelDir << std::endl;
std::map<std::string, std::string> model_path;
model_path.insert({VAD_DIR, std::string(pModelDir) + vad_sub_dir});
model_path.insert({VAD_QUANT, "true"});
model_path.insert({OFFLINE_MODEL_DIR, std::string(pModelDir) + asr_offline_sub_dir});
model_path.insert({ONLINE_MODEL_DIR, std::string(pModelDir) + asr_online_sub_dir});
model_path.insert({QUANTIZE, "true"});
model_path.insert({PUNC_DIR, std::string(pModelDir) + punc_sub_dir});
model_path.insert({PUNC_QUANT, "true"});
try {
tpass_handle = FunTpassInit(model_path, thread_num);
if (!tpass_handle) {
LOG(ERROR) << "FunTpassInit init failed";
}
// std::vector<int> chunk_size_vec = {5, 10, 5};
std::vector<int> chunk_size = {5,10,5};
float glob_beam = 3.0f;
float lat_beam = 3.0f;
float am_sc = 10.0f;
tpass_online_handle = FunTpassOnlineInit(tpass_handle, chunk_size);
decoder_handle = FunASRWfstDecoderInit(tpass_handle, ASR_TWO_PASS, glob_beam, lat_beam, am_sc);
if (!tpass_handle) {
LOG(ERROR) << "FunASRWfstDecoderInit init failed";
}
} catch (const std::exception& e) {
LOG(INFO) << e.what();
}
}
extern "C"
JNIEXPORT jstring JNICALL Java_com_fawai_asr_OnnxInter_ASRInferOffline(
JNIEnv *env, jobject /*obj*/, jbyteArray jWaveform, jboolean input_finished)
{
int size = env->GetArrayLength(jWaveform);
jbyte* waveform = env->GetByteArrayElements(jWaveform, 0);
std::vector<char> subvector(waveform, waveform + size);
try{
// result = FunOfflineInferBuffer(asr_handle, subvector.data(), subvector.size(), RASR_NONE, NULL,
// hotwords_embedding, 16000, "pcm", true, decoder_handle);
result = FunTpassInferBuffer(tpass_handle, tpass_online_handle,
subvector.data(), subvector.size(), punc_cache,
input_finished==JNI_TRUE, 16000, "pcm", (ASR_TYPE)2, hotwords_embedding, true, decoder_handle
);
if (result) {
// std::string msg = FunASRGetResult(result, 0);
// offline_res += msg;
// if (msg != "") {
// LOG(INFO) << "offline results :" << msg;
// }
// asr_handle,subvector.data(), subvector.size(),
// -1, null , hotwords_embedding,
// 16000, "pcm", true, dec_handle
// std::string tmp_sent_msg = FunASRGetStampSents(result, 0);
// tmp_sent += tmp_sent_msg;
// if (tmp_sent_msg != "") {
// LOG(INFO) << "tmp_sent results : " << tmp_sent_msg;
// offline_res = tmp_sent;
// }
std::string tmp_online_msg = FunASRGetResult(result, 0);
online_res += tmp_online_msg;
if (tmp_online_msg != "") {
LOG(INFO) << "online_res :" << tmp_online_msg;
}
std::string tmp_tpass_msg = FunASRGetTpassResult(result, 0);
tpass_res += tmp_tpass_msg;
if (tmp_tpass_msg != "") {
LOG(INFO) << "offline results : " << tmp_tpass_msg;
online_res = tpass_res;
}
FunASRFreeResult(result);
}
} catch (std::exception const &e)
{
LOG(ERROR) << e.what();
}
return env->NewStringUTF(online_res.c_str());
}
}
#endif
//这里的代码主要是看的 onnxruntime下的bin中的funasr-onnx-2passs.cpp还有include下的funasrrunonnxtime.h来构造JAVA下的函数
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(FunASRWebscoket)
set(CMAKE_CXX_STANDARD 14 CACHE STRING "The C++ version to be used.")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# set 设置 文件路径啥的
set(ONNXRUNTIME_DIR /home/sjy/cpp_ws/onnxruntime-android-1.14.0)
# 设置 ONNXRUNTIME_DIR 的路径是以下的文件路径:/home/sunyujia/cpp_ws/onnxruntime-android-1.14.0
link_directories(${ONNXRUNTIME_DIR}/lib) # 以上路径下的lib文件夹
include_directories(${ONNXRUNTIME_DIR}/include) # 以上路径下的include文件夹
set(FFMPEG_DIR /home/sjy/ffmpeg-master-latest-armv8-gpl-shared)
# 设置 FFMPEG_DIR 的路径是以下的文件路径:/home/sunyujia/cpp_ws/onnxruntime-android-1.14.0
link_directories(${FFMPEG_DIR}/lib) # 以上路径下的lib文件夹
include_directories(${FFMPEG_DIR}/include) # 以上路径下的include文件夹
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/include/) # 关联文件夹下的.h文件 也就是头文件
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/yaml-cpp/include/)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi-native-fbank)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/openfst/src/include/)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/src)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/gflags/src)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/jieba/include)
# include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/jieba/include/limonp/)
# include_directories(/home/sjy/ffmpeg-master-latest-armv8-gpl-shared/include)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/yaml-cpp yaml-cpp) # 在当前的文件夹下 完成.a文件的生成
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi-native-fbank/kaldi-native-fbank/csrc csrc)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/src src)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi kaldi)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/gflags gflags)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/openfst/src openfst)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/glog)
set(BUILD_TESTING OFF) # 设置不开启
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/glog glog) # 在当前的文件夹下 完成.a文件的生成
aux_source_directory(${PROJECT_SOURCE_DIR}/../onnxruntime/src src_files) # 查找路径下的所有源文件 保存在src_files这个变量中去!
# aux_source_directory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi kaldi_files) # 查找路径下的所有源文件 保存在src_files这个变量中去!
add_library(fawasr2pass-jni SHARED fawasr2pass.cc ${src_files} )
# add_library生成静态或者动态库 参数解析(生成的库名字, 决定是动态还是静态(默认是静态的),参数指定生成库的源文件)
target_link_libraries(fawasr2pass-jni PUBLIC avcodec avformat avutil avfilter swresample swscale )
# avcodec avformat avutil avfilter swresample swscale
target_link_libraries(fawasr2pass-jni PUBLIC onnxruntime -pthread gflags fst kaldi-util kaldi-decoder yaml-cpp dl csrc glog log)
# target_link_libraries(fawasroff-jni PUBLIC -pthread)
# target_link_libraries 添加头文件目录. -pthread