目录

·········前言

·········前期工作

·········编译工作

·········编码工作(AGC-JAVA)

·········编码工作(AGC-JNI)

·········编码工作(NS-JAVA)

 ········编码工作(NS-JNI)

·········总结

前言

       Android 单独抽取 WebRtc-AGC(音频增益) 模块

       Android 单独抽取 WebRtc-NS(音频降噪) 模块

       本文章是基于某个博客主写的移植到Android NDK上编译(这边我没有用cMake)

       https://www.cnblogs.com/mod109/p/5767867.html

       WebRtc单独模块编译的资料网上很多,零零散散,但是看了很多程序大多数都是旧的版本模块源码进行编译的,并且都是在

C++/C  的基础上去运行,很少涉及到在NDK下的编译和JNI的使用。

       后续会更新NS(降噪),aecm,aec(回音消除) 模块在NDK上编译JNI上使用的文章。

       笔者也是今年才开始正式的接触WebRt,目前正在深入分析其源代码,主要研究的是 底层模块(非算法)、Android模块,希

望后续能把一些经验分享出来。

     

前期工作

      1:Android Studio 开发工具 ,再次强调一下,这次没有使用 cMake 编译,使用的是传统的 ndk-build 编译,开发工具需要自行

配置一下,当然后面会提供源码  ,你完全可以 自己来配置cMake编译。 

      2:首先不认识WebRtc的请先百一下度,特别是模块的作用,如果是大佬的话请洗耳恭听。

      3 : audacity2.3.exe  下载一下这个工具,干什么用 搜一下就知道。

         长什么样,长这样  ↓

         

        如何导入PCM数据:文件->导入->选择PCM数据->设置对应的采样率等参数

      4:本章文重点讲解NDK、JNI等使用,需要有一定的基础适合看本文章

             

 

编译工作

     后续会把Demo上传,建议想做这些工作但是没做过的可以自行另起一个项目来做。

     首先观澜我随手一建的项目工程目录

      

       ⑴ 这个是要处理的原始音频文件,当然你也可以直接从SD卡读取,为了方便,这边直接从assets 读取。

       ⑵ AudioProcessJni 为native 加载的类

           其余为测试类和工具类。

           (里面代码写的比较乱没有整理,demo下载完后自行调整 )

       ⑶ agc文件夹是  NS和AGC编译所需的头文件和依赖文件,最开始是先调试AGC的,所以文件夹名称没有改,

            ns_jni_wrapper.c 为JNI层实现的功能

      这里贴一下Android.mk

       这玩意不简单的 , 里面有一些编译错误的默认配置项

     

      code:            

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)APP_ABI := armeabi x86LOCAL_MODULE    := webrtc_audioapp_platform:=android-21LOCAL_SRC_FILES := \        agc/complex_bit_reverse.c \        agc/complex_fft.c \        agc/cross_correlation.c \        agc/dot_product_with_scale.c \        agc/downsample_fast.c \        agc/energy.c \        agc/fft4g.c \        agc/get_scaling_square.c \        agc/min_max_operations.c \        agc/real_fft.c \        agc/resample.c \        agc/resample_48khz.c \        agc/resample_by_2.c \        agc/resample_by_2_internal.c \        agc/resample_by_2_mips.c \        agc/copy_set_operations.c \        agc/division_operations.c \        agc/spl_init.c \        agc/spl_sqrt.c \        agc/spl_sqrt_floor.c \        agc/ring_buffer.c \        agc/resample_fractional.c \        agc/splitting_filter.c \        agc/vector_scaling_operations.c \        agc/analog_agc.c \        agc/digital_agc.c \        agc/ns_core.c \        agc/nsx_core.c \        agc/nsx_core_c.c \        agc/nsx_core_neon_offsets.c \        agc/noise_suppression.c \        agc/noise_suppression_x.c \        ns_jni_wrapper.c \#undefined reference to 错误问题解决办法LOCAL_ALLOW_UNDEFINED_SYMBOLS := trueAPP_SHORT_COMMANDS := trueLOCAL_LDLIBS    := -llogAPP_CPPFLAGS := -frtti -std=c++11include $(BUILD_SHARED_LIBRARY)

  Application.mk

#APP_ABI := armeabi armeabi-v7a x86APP_ABI := armeabi x86APP_STL := stlport_staticAPP_CPPFLAGS := -frtti -std=c++11APP_SHORT_COMMANDS := trueLOCAL_LDFLAGS += -fuse-ld=bfd

 

 编码前当然你要先把so 编译过来才能调试

 编译过程....(省略)

 

           好啦,当我们已经把so库成功的编出来了,并且能正常  loadLibrary

 

编码工作(AGC-JAVA)

    首先看下 AudioProcessJni文件中对Agc 操作的native  函数有哪些?

     

public class AudioProcessJni {     static{          System.loadLibrary("webrtc_audio");  //加载native code的动态库     }     //Audio agc音频增益接口     public   native  static  void  AgcFree();     public   native  static  int   AgcFun(ByteBuffer buffer1 , short[] sArr, int frameSize);     public   native  static  long  AgcInit(long minLevel, long maxLevel,long fs);     public   native  static  void  AgcProcess();  //agc test  model}

AgcInit : 初始化agc模块功能 

AgcFun:音频增益处理函数

AgcFree:模块释放销毁

AgcProcess: 这个是增益整个搓成完全在JNI层处理,不和java 通信。

其中AgcFun中的  ByteBuffer  是java和JNI 交互数据的重点,他是java和JNI共享的一个内存块,当然你也可以给个返回值,看个人的编码习惯。

 

那么我们先来看java的测试代码:

 

 public static final  String  AGC_OUT_FILE_PATCH_DICTORY="/storage/emulated/0/Pictures/agc"; public static final  String  AGC_OUT_FILE_PATCH="/storage/emulated/0/Pictures/agc/byby_8K_1C_16bit_agc.pcm";

文件的输出目录以及输出的文件。 

  public static    void  agc_audio_test(Activity  act)  {        try {            int nbread = 0;            //读取Assets文件流            InputStream is = act.getAssets().open("byby_8K_1C_16bit.pcm");            //输出的文件目录            File  file = new File(AGC_OUT_FILE_PATCH_DICTORY);            if (!file.exists()){                boolean mkdirs = file.mkdirs();                if (mkdirs) {                    log("create dictroy success");                } else {                    log("create dictroy file");                    return;                }            }            //输出的文件            file = new File(AGC_OUT_FILE_PATCH);            //调用初始刷Agc模块            long res = AudioProcessJni.AgcInit(0, 255, 8000);            log(" AudioProcessJni.AgcInit  res = "+ res);            log("sleep 2s ");            Thread.sleep(2000);            //初始化byte转换工具            BytesTransUtil bytesTransUtil = BytesTransUtil.getInstance();            // rData 为读取的缓冲区 分配160字节            byte[] rData = new byte[160];            ByteBuffer  outBuffer = ByteBuffer.allocateDirect(160);            FileOutputStream  fos = new FileOutputStream(file);            //--------------------开始读取---------------------------            while((nbread=is.read(rData))>-1){                short[] shorts = bytesTransUtil.Bytes2Shorts(rData);                res = AudioProcessJni.AgcFun(outBuffer, shorts,80);                for (int i = 0 ;i< 80 ;i++){                    shorts[i] = (short) (outBuffer.get(2*i) + ( outBuffer.get(2*i+1) << 8));                }                  fos.write(bytesTransUtil.Shorts2Bytes(shorts),0,nbread);            }            log(" 结束Agc = " );            if (fos!=null){                fos.close();            }        } catch (IOException e) {            e.printStackTrace();            log("e:error -> "+e.toString());        } catch (InterruptedException e) {            e.printStackTrace();        }finally {            AudioProcessJni.AgcFree();        }    }

  这个是java测试的流程代码,也比较清晰,重点来讲解下以下这段代码

  

 //--------------------开始读取---------------------------            while((nbread=is.read(rData))>-1){                short[] shorts = bytesTransUtil.Bytes2Shorts(rData);                res = AudioProcessJni.AgcFun(outBuffer, shorts,80);                for (int i = 0 ;i< 80 ;i++){                    shorts[i] = (short) (outBuffer.get(2*i) + ( outBuffer.get(2*i+1) << 8));                }                  fos.write(bytesTransUtil.Shorts2Bytes(shorts),0,nbread);            }            log(" 结束Agc = " );

   ① 循环读取文件流中的数据,每次读取160个byte, 有点需要注意,底层的处理接口需要传入的是short[] 数组,文件流读取的

        byte[]数组需要转换, 这边的话在java 层转换或者在JNI层用C转换都是可以的,建议在JNI上转换,不过需要注意的是有无

        符号的问题,我这边为了方便直接在java层进行转换。

  ② Byte2Shorts 吧 byte数组转换成了short数组 并传入AgcFun [JNI层] 去处理, 返回值res < 0 是错误的 这个根据JNI层的逻辑

       去调整,我这边为了代码简洁,没有做判断。

  ③ 最后处理完的音频数据会存放在outBuffer 这个ByteBuff 的变量里,那么在上层就可以去读取它了。

       刚开始的时候以为传上来就可以用了,然后打印了数据的十六进制,发现值不一样,正负数处理溢出的问题,这时候才慢慢

       意识到,java  基本变量都是有符号的,因为底层是定义成无符号的,为什么定义成无符号这个研究JNI的时候再来说。

      那么通过

                 shorts[i] = (short) (outBuffer.get(2*i) + ( outBuffer.get(2*i+1) << 8)); 

     这个处理将数据还原成正确的。注 : 写文件操作在JNI层是很方便实现的,AgcProcess读写都是JNI层实现的,这边放到上层 

     考虑到有些人 java这边可能需要用到 这个处理完的buffer。 现在只是读取文件,其实从MIC 读取的PCM文件也基本类似。

     因此:将数据还原成了short[]之后 写入文件还要转到byte[]

       

       不知道各位小伙伴是否有更好的解决方法,或者看了我的demo之后又什么更好的解决办法一定要通知我。值得是有无符号 

       转换这一块。

 编码工作(AGC-JNI)

 现在来看下JNI的处理,其实也很简单一共3个函数先贴代码:

   初始化函数:

JNIEXPORT jlong JNICALL Java_com_webrtc_ns_AudioProcessJni_AgcInit(JNIEnv *env, jclass cls, jlong minLevel , jlong maxLevel , jlong fs){        minLevel = 0;maxLevel = 255;agc_samples  =fs;int agcMode  = kAgcModeFixedDigital;        LOGE("Java_com_webrtc_ns_AudioProcessJni_AgcInit!  -> %d \n", sizeof(short));        if ( (   WebRtcAgc_Create(&agcHandle) ) != 0) { //allocate dynamic memory on native heap for NS instance pointed by hNS.             LOGE("Noise_Suppression WebRtcNs_Create err! \n");             return  NS_ERROR;  //error occurs        }        LOGE("Java_com_webrtc_ns_AudioProcessJni_AgcCreate success! \n");        if (0 !=  WebRtcAgc_Init(agcHandle, minLevel, maxLevel, agcMode, agc_samples) )    {             LOGE("WebRtcAgc_Init WebRtcNs_Init err! \n");             return  NS_ERROR;  //error occurs    }      LOGE("Java_com_webrtc_ns_AudioProcessJni_AgcInit success! \n");        WebRtcAgc_config_t agcConfig;agcConfig.compressionGaindB = 20; //在Fixed模式下,越大声音越大agcConfig.limiterEnable     = 1;agcConfig.targetLevelDbfs   = 3;  //dbfs表示相对于full scale的下降值,0表示full scale,越小声音越大WebRtcAgc_set_config(agcHandle, agcConfig);return NS_SUCCESS;}

  处理函数 & 销毁函数:

JNIEXPORT jint JNICALL Java_com_webrtc_ns_AudioProcessJni_AgcFun(JNIEnv *env, jclass type, jobject jdirectBuff,jshortArray sArr_, jint frameSize) {    if(agc_buffer == NULL){        LOGE("gc_buffer == NULL! \n");        void* buffer = (*env)->GetDirectBufferAddress(env,jdirectBuff);        agc_buffer = buffer;    }    uint8_t saturationWarning;    int outMicLevel = 0;    int micLevelOut = 0;    int i =0 ;    int inMicLevel  = micLevelOut;    const short *pData    = NULL;    short *pOutData    = NULL;    pOutData = (short*)malloc(frameSize*sizeof(short));    pData  =(*env)->GetShortArrayElements(env,sArr_,NULL);    if(agcHandle == NULL){        LOGE("agcHandle is null! \n");        return  -3;    }    if(frameSize <= 0){        return  -2;    }    int  agcProcessResult =  WebRtcAgc_Process(agcHandle,                                               pData,                                               NULL,                                               frameSize,                                               pOutData,                                               NULL,                                               inMicLevel,                                               &outMicLevel,                                               0,                                               &saturationWarning);    if (0 !=  agcProcessResult )    {        LOGE("failed in WebRtcAgc_Process!  agcProcessResult = %d \n" ,agcProcessResult);        return  NS_ERROR ;  //error occurs    }    //memset(agc_buffer, 0,  160);    shortTobyte(80,pOutData,agc_buffer);    (*env)->ReleaseShortArrayElements(env, sArr_, pData, 0);    return  AGC_SUCCESS;}JNIEXPORT void JNICALL Java_com_webrtc_ns_AudioProcessJni_AgcFree(JNIEnv *env , jclass  cls){    WebRtcAgc_Free(agcHandle);}

① 初始化函数看起来很简单,确实很简单。

    关于一下

 WebRtcAgc_config_t agcConfig; agcConfig.compressionGaindB = 20; //在Fixed模式下,越大声音越大 agcConfig.limiterEnable     = 1; agcConfig.targetLevelDbfs   = 3;  //dbfs表示相对于full scale的下降值,0表示full scale,越小声音越大

   可以自己编译调试, 用工具去比对效果。

②  void* buffer = (*env)->GetDirectBufferAddress(env,jdirectBuff);   获取java层分配的ByteBuff 实例,最后一个 char指针指向了

      这个 实例,需要注意的是 这里 

    unsigned  char* agc_buffer = NULL;   

      是无符号的,如果有符号的话后面可能会有溢出问题,所以在底层char指针表示的我这边都用无符号。

       WebRtcAgc_Process 函数处理数据最后得到 short * 的数据 , 最后通过 shortTobyte 函数将short 的值赋给 ByteBuff 的实

      例,这样java层就能得到这个数据。

③释放工作比较简单    WebRtcAgc_Free  即可。

 

 编码工作(NS-JAVA)

 

  降噪模块基本流程和增益模块大同小异。

  目前处理的是8K采样率音频, 如果处理32K采样率音频,那么可能需要传入高频,低频数据做处理。

  

音频降噪部分较为简单,用起来也就几个函数,除了需要传入的音频数据以外,需要调整的参数也就是音频采样率和降噪等级。另外这部分代码采用纯C语言语法编写,可以跨平台编译。整个算法也不算特别复杂,运行起来占CPU也不是很多,可以上至i7 8核CPU的高配电脑,下至380Mhz的小嵌入式系统以及一切版本的移动端产品中编译运行。另外效果也十分不错,通过本文附带的测试demo大家就可以感受一下。

降噪有两部分代码,一套是定点算法(noise_suppression_x.h),一套是浮点算法(noise_suppression.h)。相对来说浮点算法精度更高,但是耗系统资源更多,特别是浮点计算能力较弱的低端ARM CPU上。但是一般来说浮点和定点算法在实际效果上听不出区别出来,估计是我没遇到过必须必须要用浮点的情况。在使用上,浮点和定点也仅仅只是变量名和函数没中多出了一个x。

音频处理的时候webrtc一次仅能处理10ms数据,小于10ms的数据不要传入,因为即时是传入小于10ms的数据最后传入也是按照10ms的数据传出,此时会出现问题。另外支持采样率也只有8K,16K,32K三种,不论是降噪模块,或者是回声消除增益等等均是如此。对于8000采样率,16bit的音频数据,10ms的时间采样点就是80个,一个采样点16bit也就是两个字节,那么需要传入WebRtcNsx_Process的数据就是160字节。对于8000和16000采样率的音频数据在使用时可以不管高频部分,只需要传入低频数据即可,但是对于32K采样率的数据就必须通过滤波接口将数据分为高频和低频传入,传入降噪后再组合成音频数据。大于32K的音频文件就必须要通过重采样接口降频到对应的采样率再处理,在demo源码里面有对应的接口使用者可以去查。

降噪的开源代码包括定点降噪,浮点降噪,音频重采样,滤波接口,抠出来后修改了头文件包含位置使其都在同一目录下,如果是xcode下编译可能会有once函数编译不过的问题,此时修改一个宏即可,为了尽量避免修改问题就不改动这部分了。

示例代码给了32K采样率的测试demo,也有8K采样率实现。16K采样率只需要将8K内部的数据大小由80改成160即可,PCM音频文件可以由Audacity软件通过文件--导入--原始数据,选择好bit位数,声道,采样率即可显示波形,播放。

public class TestNs {    public static final  String  AGC_OUT_FILE_PATCH_DICTORY="/storage/emulated/0/Pictures/ns";    public static final  String  AGC_OUT_FILE_PATCH="/storage/emulated/0/Pictures/ns/byby_8K_1C_16bit_ns_android.pcm";    public  static    void  ns_audio_test(Activity act)  {        try {            File file = null;            InputStream is = act.getAssets().open("byby_8K_1C_16bit.pcm");            FileOutputStream fos = null;            file = new File(AGC_OUT_FILE_PATCH_DICTORY);            if (!file.exists()){                boolean mkdirs = file.mkdirs();                if (mkdirs) {                    log("create dictroy success");                } else {                    log("create dictroy file");                    return;                }            }            file = new File(AGC_OUT_FILE_PATCH);            fos = new FileOutputStream(file);            log("sleep 2s ");            Thread.sleep(2000);            long res = AudioProcessJni.initiateNSInstance(8000,3);            if (res == 7 ){                //success+            }            BytesTransUtil bytesTransUtil = BytesTransUtil.getInstance();            byte[] rData = new byte[160];            ByteBuffer outBuffer  =  ByteBuffer.allocateDirect(160);            int nbread = 0;            long startTime = System.currentTimeMillis();            while((nbread=is.read(rData))>-1){                short[] shorts = bytesTransUtil.Bytes2Shorts(rData);                // ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(data);                  res = AudioProcessJni.processNS(outBuffer, shorts, 80);                for (int i = 0 ;i< 80 ;i++){                    shorts[i] = (short) ( (outBuffer.get(2*i)&0x00FF )  + ( outBuffer.get(2*i+1) << 8));                }               fos.write(bytesTransUtil.Shorts2Bytes(shorts),0,nbread);            }            long endTime = System.currentTimeMillis();            log(" 结束 Ns = 程序运行时间:"+(endTime-startTime)+"ms");            if (fos!=null){                fos.close();            }        } catch (IOException e) {            e.printStackTrace();            log("e:error -> "+e.toString());        } catch (InterruptedException e) {            e.printStackTrace();        }finally {        }    }

 编码工作(NS-JNI)

 初始化函数  Java_com_webrtc_ns_AudioProcessJni_initiateNSInstance

 降噪处理函数   Java_com_webrtc_ns_AudioProcessJni_processNS

 销毁函数  Java_com_webrtc_ns_AudioProcessJni_destoryNS

//初始化频率的降噪结构体参数/* * nSample:采集数据的频率 */JNIEXPORT jint JNICALL Java_com_webrtc_ns_AudioProcessJni_initiateNSInstance(JNIEnv *env, jclass cls,  jlong nSample, jint nMode){    //创建webrtc降噪处理句柄    //NsHandle *hNS = NULL; //create a pointer to NsHandle on native stack.    if ( (  WebRtcNs_Create(&pNS_inst) ) !=  0) { //allocate dynamic memory on native heap for NS instance pointed by hNS.        LOGE("Noise_Suppression WebRtcNs_Create err! \n");        return  NS_ERROR;  //error occurs    }    if (0 !=  WebRtcNs_Init(pNS_inst,nSample)){LOGE("Noise_Suppression WebRtcNs_Init err! \n");return  NS_ERROR;  //error occurs}if (0 !=  WebRtcNs_set_policy(pNS_inst,nMode)){printf("Noise_Suppression WebRtcNs_set_policy err! \n");return  NS_ERROR;  //error occurs}   // return ((int) (NSinst_t *) pNS_inst); //returns the address of NS instance on native heap.      return NS_SUCCESS;}

  

JNIEXPORT jint JNICALL  Java_com_webrtc_ns_AudioProcessJni_processNS(JNIEnv *env, jclass type, jobject jdirectBuff,jshortArray outframe_,jint sf) {    jshort *outframe = (*env)->GetShortArrayElements(env, outframe_, NULL);    short *pOutData    = NULL;    int frameSize =sf;    if(pNS_inst == NULL){        LOGE("nsHandle is null! \n");       return  -3;   }    if(ns_buffer == NULL){        LOGE("gc_buffer == NULL! \n");        void* buffer = (*env)->GetDirectBufferAddress(env,jdirectBuff);        ns_buffer = buffer;    }    pOutData = (short*)malloc(frameSize*sizeof(short));    if ( WebRtcNs_Process(pNS_inst, outframe, NULL, pOutData,NULL) != 0){        LOGE("failed in WebRtcAgc_Process! \n" );        return  NS_ERROR ;  //error occurs    }    shortTobyte(80,pOutData,ns_buffer);    (*env)->ReleaseShortArrayElements(env, outframe_, outframe, 0);    return  AGC_SUCCESS;}
JNIEXPORT jint JNICALL Java_com_webrtc_ns_AudioProcessJni_destoryNS(JNIEnv *env, jclass cls){        WebRtcNs_Free(pNS_inst);}

 处理32K语言

    以下当 sf=32*1000 时,进入处理32K语言的过程; 

    此过程全程在JNI中执行,读取pcm文件进行降噪处理

/*JNI全处理*/JNIEXPORT void JNICALL  Java_com_webrtc_ns_AudioProcessJni_NSProcess(JNIEnv *env, jclass type ,jint sf) {    const char *sFile     = "/storage/emulated/0/Pictures/ns/lhydd_1C_16bit_32K.pcm";    const char *dFile     ="/storage/emulated/0/Pictures/ns/lhydd_1C_16bit_32K_ns.pcm";    const char *sFile_8k     = "/storage/emulated/0/Pictures/ns/byby_8K_1C_16bit.pcm";    const char *dFile_8k     ="/storage/emulated/0/Pictures/ns/byby_8K_1C_16bit_ns.pcm";    // TODO  test agc model    char *pInBuffer = NULL;    char *pOutBuffer = NULL;    int i = 0;    long nFileSize = 0;    if(sf == 32*1000) {        FILE * fpIn = fopen(sFile, "rb");        FILE * fpOut = fopen(dFile, "wb");        if(fpIn == NULL || fpOut == NULL){            LOGE("file open filed");            return;        }                LOGE("NS Java_com_webrtc_ns_AudioProcessJni_NSProcess  32K   start");                do {                    fseek(fpIn, 0, SEEK_END);                    nFileSize = ftell(fpIn);                    printf("nFileSize = %d  \n ", nFileSize);                    fseek(fpIn, 0, SEEK_SET);                    pInBuffer = (char *) malloc(nFileSize);                    memset(pInBuffer, 0, nFileSize);                    fread(pInBuffer, sizeof(char), nFileSize, fpIn);                    pOutBuffer = (char *) malloc(nFileSize);                    memset(pOutBuffer, 0, nFileSize);                    int filter_state1[6], filter_state12[6];                    int Synthesis_state1[6], Synthesis_state12[6];                    memset(filter_state1, 0, sizeof(filter_state1));                    memset(filter_state12, 0, sizeof(filter_state12));                    memset(Synthesis_state1, 0, sizeof(Synthesis_state1));                    memset(Synthesis_state12, 0, sizeof(Synthesis_state12));                    for (i = 0; i < nFileSize; i += 640) {                        if (nFileSize - i >= 640) {                            short shBufferIn[320] = {0};                            short shInL[160], shInH[160];                            short shOutL[160] = {0}, shOutH[160] = {0};                            memcpy(shBufferIn, (char *) (pInBuffer + i), 320 * sizeof(short));                            //首先需要使用滤波函数将音频数据分高低频,以高频和低频的方式传入降噪函数内部                            WebRtcSpl_AnalysisQMF(shBufferIn, 320, shInL, shInH, filter_state1,                                                  filter_state12);                            //将需要降噪的数据以高频和低频传入对应接口,同时需要注意返回数据也是分高频和低频                            if (0 == WebRtcNs_Process(pNS_inst, shInL, shInH, shOutL, shOutH)) {                                short shBufferOut[320];                                //如果降噪成功,则根据降噪后高频和低频数据传入滤波接口,然后用将返回的数据写入文件                                WebRtcSpl_SynthesisQMF(shOutL, shOutH, 160, shBufferOut, Synthesis_state1,                                                       Synthesis_state12);                                memcpy(pOutBuffer + i, shBufferOut, 320 * sizeof(short));                            }                        }                    }                    fwrite(pOutBuffer, sizeof(char), nFileSize, fpOut);                } while (0);                    LOGE("NS 结束");                    WebRtcNs_Free(pNS_inst);                    fclose(fpIn);                    fclose(fpOut);                    free(pInBuffer);                    free(pOutBuffer);    } else{        FILE * fpIn = fopen(sFile_8k, "rb");        FILE * fpOut = fopen(dFile_8k, "wb");        if(fpIn == NULL || fpOut == NULL){            LOGE("file open filed");            return;        }        LOGE("NS Java_com_webrtc_ns_AudioProcessJni_NSProcess  8K   start");        int len;        int frameSize =80;        int i = 0 ;        const  short *pData    = NULL;        short *pOutData = NULL;        pData    = (short*)malloc(frameSize*sizeof(short));        pOutData = (short*)malloc(frameSize*sizeof(short)); //160        len = frameSize*sizeof(short);        while(1)        {            memset(pData, 0, len);            if (len > 0)            {                len = fread(pData, 1, len, fpIn);                int nSRet = WebRtcNs_Process(pNS_inst, pData, NULL, pOutData,NULL);                if (nSRet != 0)                {                    LOGE("failed in WebRtcAgc_Process\n");                    break;                }                  fwrite(pOutData, 1, len, fpOut);            } else {                break;            }        }        LOGE("NS 结束");        WebRtcNs_Free(pNS_inst);        fclose(fpIn);        fclose(fpOut);        free(pInBuffer);        free(pOutBuffer);    }}

 总结

          总结一句话,给你们代码就是了,下载地址:

                     https://download.csdn.net/download/gjy_it/11771371

更多相关文章

  1. Android中消息传递,看这一篇足够了
  2. Android(安卓)数据存储(二) 文件的使用
  3. Android(安卓)数据保存
  4. Android(安卓)Binder
  5. 安卓017ListView & GridView & ScrollView
  6. 2013.09.02——— android 处理音频焦点
  7. Android数据存取之Databases
  8. android 利用ksoap2方式连接webservice
  9. 编译Android内核

随机推荐

  1. Android 系统 目录 分析
  2. Android使用selector自定义按钮
  3. Android手机端加载电脑端网页
  4. Android系统的Binder机制之一——Service
  5. Fix bug in the notepad tutorial of And
  6. Android下引用系统库的方法及问题
  7. [日更-2019.4.22、23、24] cm-14.1 Andro
  8. Android地图应用开发之--百度地图集成及
  9. 【Android】Android中两种常用布局(Linear
  10. 解决AndroidStudio连不上Android设备真机