乐趣区

关于openharmony:啃论文俱乐部移植speexdsp到OpenHarmony标准系统⑤

  • 大家好!我来自南京,在 OpenHarmony 成长打算啃论文俱乐部,与 华为、软通能源、润和软件、拓维信息、深开鸿 等公司一起,学习和钻研 操作系统技术
    从往年 1 月 11 日退出 OpenHarmony 俱乐部曾经有靠近 8 个月工夫了。笔者始终在思考啃论文给我带来了些什么,通过啃论文能为 OpenHarmony 做些什么。笔者利用大二升大三寒假两个月工夫移植了 Speexdsp 这个三方库到 OpenHarmony 规范零碎,而对于后面的问题我仿佛找到了答案,现将啃论文和三方库移植分享教训如下:

因为想要分享的内容较多,为防止读者姥爷们失去看上来的急躁,分享将以连载的形式进行。感激润和软件提供的硬件反对。

下期预报:OAT 开源扫描和三方库上仓根本要求

本期为 移植 speexdsp 到 OpenHarmony 规范零碎 的第⑤期,次要内容如下:
@toc


speexdsp 移植后已提交至 openhamrony sig 仓库:https://gitee.com/openharmony…


七、Speexdsp 功能分析

  • 将 speexdsp 退出 openharmony 编译体系后,能胜利编译进去动态链接库和测试用的可执行文件,并不代表移植三方库胜利。还要在开发板上运行测试其性能是否失常。

speexdsp 外围库剖析

1. 库实现形式

  • 编程语言:C
  • 原生平台:linux

2. 依赖剖析

  • 除 C 规范库外,无其余第三方库依赖

3.license 以及版权

  • 依据 speex 官网 https://speex.org/ 的信息,speexdsp 应用的开源协定为 revised BSD license(revised BSD license 又称为 3-clause BSD License 或者BSD 3-Clause License,个别应用 BSD 3-Clause)
  • OpenHamorny 第三方开源软件许可证类型必须是 OSI 明确定义的。
  • OSI明确定义的开源许可证有:https://opensource.org/licens…
  • BSD 3-Clause LicenseOSI 明确定义的开源许可。

如下类型许可证能够引入到 OpenHarmony 我的项目中:

Apache License 2.0
Mulan Permissive Software License, Version 2
BSD 2-clause
BSD 3-clause
DOM4J License
PostgreSQL License
Eclipse Distribution License 1.0
MIT
ISC
ICU
University of Illinois/NCSA
W3C Software License
zlib/libpng
Academic Free License 3.0
Python Software Foundation License
Python Imaging Library Software License
Boost Software License Version 1.0
WTF Public License
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
Zope Public License 2.0

如下类型许可证不倡议引入到 OpenHarmony 我的项目中:

GNU GPL 1, 2, 3
GNU Affero GPL 3
GNU LGPL 2, 2.1, 3
QPL
Sleepycat License
Server Side Public License (SSPL) version 1
Code Project Open License (CPOL)
BSD-4-Clause/BSD-4-Clause (University of California-Specific)
Facebook BSD+Patents license
NPL 1.0/NPL 1.1
The Solipsistic Eclipse Public License
The "Don't Be A Dick" Public License
JSON License
Binary Code License (BCL)
Intel Simplified Software License
JSR-275 License
Microsoft Limited Public License
Amazon Software License (ASL)
Java SDK for Satori RTM license
Redis Source Available License (RSAL)
Booz Allen Public License
Creative Commons Non-Commercial
Sun Community Source License 3.0
Common Development and Distribution Licenses: CDDL 1.0 and CDDL 1.1
Common Public License: CPL 1.0
Eclipse Public License: EPL 1.0
IBM Public License: IPL 1.0
Mozilla Public Licenses: MPL 1.0, MPL 1.1, and MPL 2.0
Sun Public License: SPL 1.0
Open Software License 3.0
Erlang Public License
UnRAR License
SIL Open Font License
Ubuntu Font License Version 1.0
IPA Font License Agreement v1.0
Ruby License
Eclipse Public License 2.0: EPL 2.0

speexdsp 的 license 以及版权内容如下:

Copyright 2002-2008     Xiph.org Foundation
Copyright 2002-2008     Jean-Marc Valin
Copyright 2005-2007    Analog Devices Inc.
Copyright 2005-2008    Commonwealth Scientific and Industrial Research
                        Organisation (CSIRO)
Copyright 1993, 2002, 2006 David Rowe
Copyright 2003         EpicGames
Copyright 1992-1994    Jutta Degener, Carsten Bormann

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

4. 最新一次版本

  • 2022 年 6 月 16 日, 版本号 1.2.1

    5. 代码规模

linux 零碎提供了 wc 命令来统计文件的行数,统计当前目录下的所有文件行数,终端输出如下命令:

wc -l *
文件名 代码行数
arch.h 232
bfin.h 15
buffer.c 176
fftwrap.c 448
fftwrap.h 58
filterbank.c 227
filterbank.h 66
fixed_arm4.h 135
fixed_arm5e.h 160
fixed_bfin.h 141
fixed_debug.h 497
fixed_generic.h 106
jitter.c 839
kiss_fft.c 523
_kiss_fft_guts.h 160
kiss_fft.h 108
kiss_fftr.c 297
kiss_fftr.h 51
math_approx.h 332
mdf.c 1279
misc_bfin.h 56
os_support.h 169
preprocess.c 1215
pseudofloat.h 379
resample.c 1239
resample_neon.h 339
resample_sse.h 128
scal.c 293
smallft.c 1261
smallft.h 46
vorbis_psy.h 97
speex_buffer.h 68
speexdsp_config_types.h 12
speexdsp_types.h 126
speex_echo.h 170
speex_jitter.h 197
speex_preprocess.h 219
speex_resampler.h 343
总行数 12207

功能分析

能够参考 speexdsp 提供的文档剖析性能

预处理器

预处理器被设计为在运行编码器之前在音频上应用。预处理器提供三个次要性能:

  • 噪声克制
  • 自动增益管制(AGC)
  • 语音流动检测(V AD)

自适应抖动缓冲区

  • 当通过 UDP 或 RTP 传输语音 (或任何相干内容) 时,包可能会失落,以不同的提早达到,甚至乱序。
  • 抖动缓冲区的目标是从新排序数据包,并缓冲足够长的工夫,以便它们能够被发送以进行解码。

声学回声消除器

回声打消是为了进步远端品质。

  • 在任何免提通信零碎中,远端语音通过本地扬声器播放。音频在房间内流传,并被麦克风捕捉。如果从麦克风捕捉的音频被间接发送到远端,那么用户就会听到远端语音的回声。声学回声消除器设计用于在声学回声发送到远端之前打消它。

重采样器

这个重采样器能够用于在任意两个速率之间进行转换(比率必须是有理数),并且能够管制品质 / 复杂性的衡量。

  • 重采样器在某些状况下将音频从一个采样率转换到另一个采样率。
  • 它能够用于混合具备不同采样率的流、用于反对声卡不反对的采样率、用于转码等。

八、Speexdsp 功能测试

测试逻辑

  • 在 speexdsp 原生库的 libspeexdsp 目录下有原生的测试源文件 testresample.c、testresample2.c、testecho.c、testdenoise.c、testjitter.c。
  • 进行功能测试须要比照 pc 端开发板 的运行成果,因而须要在 pc 端编译出测试用的可执行文件(开发板上的曾经编译进去了)。

重采样性能

  • 查看源码可知,运行测试重采样率的可执行文件时,输出一份音频文件的同时须要指定解决后输入的音频文件。
  • 测试重采样性能的源文件为 testresample.c 和 testresample2.c。

testresample.c 源码剖析如下:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

// 要应用重采样器,必须蕴含它的头文件 speex_resampler.h:
#include "speex/speex_resampler.h"
// 根本输入输出函数的申明
#include <stdio.h>
//// 头文件 <math.h> 中申明了一些数学函数和宏
#include <math.h>

/*
stdlib.h 中,蕴含了 C 语言的一些罕用库函数。如动态内存相干的 malloc, realloc,zalloc,calloc,free 等。随机数相干的 rand,srand 等。零碎相干的 system, getenv,setenv 等。字符串转数值函数,atoi, atof,strtoul 等。如果在代码中,调用了这个头文件中的函数或者宏定义,则需援用该头文件。*/
#include <stdlib.h>

//NN 定义的是帧长度
#define NN 256

int main()
{
   spx_uint32_t i;
   short *in;
   short *out;
   float *fin, *fout;
   int count = 0;

// 对于每一个被重采样的流(流是一种形象的概念, 示意一连串的数据元素; 流中的数据元素称为帧 Frame。),有必要创立一个重采样状态:SpeexResamplerState *resampler;
//resampler = speex_resampler_init(nb_channels, input_rate, output_rate, quality, &err);
// nb_channels 声道数量,这段测试程序要求输出的音频声道数量为 1
// input_rate 和 output_rate 指的是输出音频的采样率和输入音频的采样率。// err 错误码
/*
    quality 是语音编解码器方面的概念,范畴是 0~10. 通常,对于个别应用品质为 3 是能够承受的,而对于业余音频工作,品质为 10 是最举荐的。品质 0 通常具备良好的声音(当然比应用线性插值重采样更好),但可能会听到伪影。*/
/* 在数字音频畛域,罕用的采样率有:8000 Hz - 电话所用采样率,对于人的谈话曾经足够
        11025 Hz - 电话所用采样率
        22050 Hz - 无线电播送所用采样率
        32000 Hz - miniDV 数码视频 camcorder、DAT (LP mode)所用采样率
        44100 Hz - 音频 CD, 也罕用于 MPEG-1 音频(VCD,SVCD,MP3)所用采样率
        47250 Hz - 商用 PCM 录音机所用采样率
        48000 Hz - miniDV、数字电视、DVD、DAT、电影和业余音频所用的数字声音所用采样率
        50000 Hz - 商用数字录音机所用采样率
*/
   SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10, NULL);

//96000 是输出音频的采样率,44100 是输入音频的采样率。单位为 Hz
   speex_resampler_set_rate(st, 96000, 44100);

   speex_resampler_skip_zeros(st);

 /* 
   malloc 函数的作用是让零碎寻找闲暇地址后为你调配一块指定大小的空间来给你应用,这一块空间其实要比你申请的空间大一些,它蕴含两个局部:1. 你申请的空间;2. 记录这个空间信息的空间。*/
   in = malloc(NN*sizeof(short));
   out = malloc(2*NN*sizeof(short));
   fin = malloc(NN*sizeof(float));
   fout = malloc(2*NN*sizeof(float));

//while(1): 这是一个死循环,始终在 while 里循环.
// 调试代码时,为了检测一部分代码是否 OK,可加测试点 while(1), 测试这段代码。while (1)
   {
      spx_uint32_t in_len;
      spx_uint32_t out_len;
/* 从终端获取音频数据 */
      fread(in, sizeof(short), NN, stdin);

//feof()是检测流上的文件结束符的函数,如果文件完结,则返回非 0 值,否则返回 0
      if (feof(stdin))
         break;
      for (i=0;i<NN;i++)
         fin[i]=in[i];
      in_len = NN;
      out_len = 2*NN;
      /*if (count==2)
         speex_resampler_set_quality(st, 10);*/

// 理论的重采样是应用 speex_resampler_process_int(resampler, channelID, in, &in_length, out, &out_length);
// 其中 "channelID" 是输出的音频的声道。对于单声道,应用 0。也能够同时解决多个通道。// 其中 "in" 指针指向所选通道的输出缓冲区的第一个样本,输入指向输入的第一个样本。//in_length 和 out_length 别离指定输出和输入缓冲区的大小。speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len);
      for (i=0;i<out_len;i++)
         out[i]=floor(.5+fout[i]);
      /*speex_warning_int("writing", out_len);*/

/* 转换后的数据输出到终端显示 */
      fwrite(out, sizeof(short), out_len, stdout);
      count++;
   }
   speex_resampler_destroy(st);

//free 函数承受一个指针,而后将指针指向的地址还给零碎。(但它不会扭转指针的指向,所以个别在 free 之后还要将指针置
   空,不然你的这个指针就会变成野指针)// 一般来说,malloc 函数应该和 free 函数成对呈现,避免向零碎要的内存太多零碎不快乐。free(in);
   free(out);
   free(fin);
   free(fout);
   return 0;
}

能够得悉:

  • 输出音频的采样率要求为 96000Hz、声道为单声道。
  • 输入音频的采样率为 44100。

回声打消性能

  • 运行测试回声打消的可执行文件时,须要输出两段音频文件,别离为一份麦克风的音频、一份 speaker 的音频。另外须要指定一份解决后输入的音频文件。采样率都为 8000Hz
  • 测试回声打消性能的源文件为 testecho.c。
    testecho.c 源码剖析如下:
/* 
Speex 源码中附带的这个例子,只适宜于串行的链式媒体流,当媒体播放、媒体采集、媒体网
络数据接口分属在不同现成时,就会存在同步问题,异步线程会导致信号提早加大,回声打消收敛成果不好。*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* 应用回声消除器须要加 #include "speex/speex_echo.h"*/
#include "speex/speex_echo.h"
/* 应用预处理器须要增加 #include "speex/speex_preprocess.h"*/
#include "speex/speex_preprocess.h"
#include <stdio.h>
//stdlib 头文件即 standard library 规范库头文件 
#include <stdlib.h>
// sys/types.h 中文名称为根本零碎 数据类型。在应用程序源文件中蕴含 <sys/types.h> 以拜访 _LP64 和 _ILP32 的定义
#include <sys/types.h> 
//stat.h 头文件,轻松获取文件属性
#include <sys/stat.h> 
//fcntl.h 相干函数 open,fcntl,shutdown,unlink,fclose
#include <fcntl.h> 

//NN 是 frame_size 帧长度,TAIL 是 filter_length 滤波器长度
#define NN 128
#define TAIL 1024 

// 当你须要程序带参数地启动的时候,就用 int main(int argc, char *argv[])
int main(int argc, char **argv) 
{//FILE* 指针作为文件句柄,是文件拜访的惟一标识,它由 fopen 函数创立,fopen 关上文件胜利,则返回一个无效的 FILE* 指针,否则返回空指针 NULL //[nʌl]
   FILE *echo_fd, *ref_fd, *e_fd;
   short echo_buf[NN], ref_buf[NN], e_buf[NN];
   SpeexEchoState *st;
   SpeexPreprocessState *den;
// 采样率为 8000. 单位为 hz
   int sampleRate = 8000;

   if (argc != 4)
   {fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");
      exit(1);
   }

// fopen 函数用于关上文件
   echo_fd = fopen(argv[2], "rb");
   ref_fd  = fopen(argv[1],  "rb");
   e_fd    = fopen(argv[3], "wb");

/*
1. 创立一个回声打消状态:SpeexEchoState *echo_state = speex_echo_state_init(frame_size, filter_length);
前边的语句 SpeexEchoState *st;  
2.NN 是 frame_size 帧长度,TAIL 是 filter_length 滤波器长度
*/·
   st = speex_echo_state_init(NN, TAIL);
   den = speex_preprocess_state_init(NN, sampleRate);
   speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);
/*
如果你想进一步缩小信号中的回波,你能够通过将回波消除器与预处理器相关联来实现. 这是通过调用:
speex_preprocess_ctl(preprocess_state, SPEEX_PREPROCESS_SET_ECHO_STATE,echo_state);
*/
   speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);
   while (!feof(ref_fd) && !feof(echo_fd))
   {fread(ref_buf, sizeof(short), NN, ref_fd);
      fread(echo_buf, sizeof(short), NN, echo_fd);
/* 创立回声消除器状态后,能够通过以下形式解决音频:speex_echo_cancellation(echo_state, input_frame, echo_frame, output_frame); 
其中,input_frame 是麦克风捕捉到的音频,echo_frame 是扬声器播放的信号(须要去除),output_frame 是去除回声的信号。*/
      speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);
      speex_preprocess_run(den, e_buf);
      fwrite(e_buf, sizeof(short), NN, e_fd);
   }
   speex_echo_state_destroy(st); 
// 能够用以下办法打消回声对消状态:speex_echo_state_destroy(echo_state);
   speex_preprocess_state_destroy(den);
// fclose(FILE *fp) 个别地,fclose(fp)应与 fopen 配对应用,特地是含有写形式的文件,若不敞开,可能会造成文件数据失落。fclose(e_fd);
   fclose(echo_fd);
   fclose(ref_fd);
   return 0;
}

预处理性能

  • 运行测试预处理性能的可执行文件时,输出一份音频文件的同时须要指定解决后输入的音频文件。(采样率为 8000Hz)
  • 测试源文件 testdenoise.c 测试的是预处理性能中的噪声克制。

testdenoise.c 源码剖析如下:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// 应用预处理性能先 #include "speex/speex_preprocess.h"
#include "speex/speex_preprocess.h"
#include <stdio.h>
// 定义 NN 为 160
#define NN 160

int main()
{short in[NN];
   int i;
/*
而后,能够创立一个预处理器状态:SpeexPreprocessState *preprocess_state = speex_preprocess_state_init(frame_size,sampling_rate);
preprocess_state(预处理状态)frame_size 指的是帧长度
sampling_rate 指的是采样率
*/
   SpeexPreprocessState *st;
   int count=0;
   float f;

/*frame_size(帧长度)为 160,采样率为 8000*/
   st = speex_preprocess_state_init(NN, 8000);

/* 预处理器的行为能够通过以下形式扭转:speex_preprocess_ctl(preprocess_state, request, ptr);*/

/*SPEEX_PREPROCESS_SET_DENOISE Turns denoising on(1) or off(2) (spx_int32_t)*/
   i=1; // i= 1 就是关上预处理器的降噪性能;i= 2 就是敞开降噪性能
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i); 

/*SPEEX_PREPROCESS_SET_AGC Turns automatic gain control (AGC) on(1) or off(2) (spx_int32_t)*/
/*AGC 全称是自动增益管制,作用是针对不同的强度的信号应用不同的增益进行放大,使得信号最终的输入幅度维持在同一规范 */
   i=0; // 
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);

   i=8000;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i);

/*SPEEX_PREPROCESS_SET_DEREVERB Turns reverberation removal on(1) or off(2) (spx_int32_t)*/
//reverberation removal 混响打消
   i=0;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i);

   f=.0;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);

   f=.0;
   speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);

/* while(1): 这是一个死循环,始终在 while 里循环, 调试代码时,为了检测一部分代码是否 OK,可加测试点 while(1), 测试这段代码 */
   while (1)
   {
      int vad;
      /*C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。*/
      fread(in, sizeof(short), NN, stdin);
/*
feof()是检测流上的文件结束符的函数,如果文件完结,则返回非 0 值,否则返回 0
个别在文件操作,中常常应用 feof()判断文件是否完结。*/
      if (feof(stdin))
         break;
/*
对于每个输出帧,须要调用:speex_preprocess_run(preprocess_state, audio_frame);
其中 audio_frame 被用作输出和输入。*/
//fwrite 和 fread 是以记录为单位的 I / O 函数,fread 和 fwrite 函数个别用于二进制文件的输入输出。vad = speex_preprocess_run(st, in);
      /*fprintf (stderr, "%d\n", vad);*/
      fwrite(in, sizeof(short), NN, stdout);
      count++;
   }
// 预处理器状态能够通过以下形式销毁:speex_preprocess_state_destroy(preprocess_state);
   speex_preprocess_state_destroy(st);
   return 0;
}

抖动缓冲性能

当通过 UDP 或 RTP 传输语音 (或任何相干内容) 时,包可能会失落,以不同的提早达到,甚至乱序。

1. 抖动缓冲区的目标是从新排序数据包,并缓冲足够长的工夫,以便它们能够被发送以进行解码。

2. 测试源文件 testjitter.c,这个去抖动测试须要接管来自 udp/rtp 的网络语音数据,原生测试程序没有做到真正意义上的测试,从程序上看是通知用户如何应用接口。

testjitter.c 源码剖析:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/*jitter buffer 能够通过以下形式启用:#include <speex/speex_jitter.h>*/
#include "speex/speex_jitter.h"
#include <stdio.h>

union jbpdata {  
/*
联结类型的申明,union 是联合体关键字; 联结是一种非凡的自定义类型,该种类型定义的变量也蕴含一系列的成员,特色是这些成员共用同一块空间,所以联合体也被称为共用体。抖动缓冲器是一个共享的数据区域
*/
  unsigned int idx; 
//unsigned int 是整数类型,存储大小为 2 或 4 字节,值范畴为 0 到 65,535 或 0 到 4,294,967,295
//unsigned char 的示意范畴为 0~255 此处定义了一个领有四个元素的数组
  unsigned char data[4];
};

void synthIn(JitterBufferPacket *in, int idx, int span) {
  union jbpdata d;
  d.idx = idx;

  in->data = d.data;
  in->len = sizeof(d);
  in->timestamp = idx * 10;
  in->span = span * 10;
  in->sequence = idx;
  in->user_data = 0;
}

void jitterFill(JitterBuffer *jb) {char buffer[65536];
   JitterBufferPacket in, out;
   int i;

   out.data = buffer;

   jitter_buffer_reset(jb);

   for(i=0;i<100;++i) {synthIn(&in, i, 1);
     jitter_buffer_put(jb, &in);

     out.len = 65536;

     /*
     当解码器筹备解码数据包时,须要解码的数据包能够通过以下形式取得:
     int start_offset;
     err = jitter_buffer_get(state, &packet, desired_span, &start_offset);
     */
    // 如果从不同的线程调用 jitter_buffer_put()和 jitter_buffer_get(),那么须要应用互斥锁来爱护 jitter 缓冲区状态。if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) {printf("Fill test failed iteration %d\n", i);
     }
     if (out.timestamp != i * 10) {printf("Fill test expected %d got %d\n", i*10, out.timestamp);
     }
/* 因为 jitter 缓冲区被设计为不应用显式计时器,所以须要显式地通知它工夫。这是通过调用:jitter_buffer_tick(state);
*/
     jitter_buffer_tick(jb);
   }
}

/*
当一个包达到时,它须要通过以下形式插入到 jitter buffer 中:
JitterBufferPacket packet;
jitter_buffer_put(state, &packet);
*/
int main()
{char buffer[65536];
   JitterBufferPacket in, out;
   int i;

   /* 新的抖动缓冲状态能够通过以下形式初始化:JitterBuffer *state = jitter_buffer_init(step);
   step 参数是用于调整提早的默认工夫步长还有做暗藏,step 参数的值总是为 1,也能够是更高的值。*/

   JitterBuffer *jb = jitter_buffer_init(10);

   out.data = buffer;

   /* Frozen sender case */
   jitterFill(jb);
   for(i=0;i<100;++i) {
     out.len = 65536;
     jitter_buffer_get(jb, &out, 10, NULL);
     jitter_buffer_tick(jb);
   }
   synthIn(&in, 100, 1);
   jitter_buffer_put(jb, &in);
   out.len = 65536;
   if (jitter_buffer_get(jb, &out, 10, NULL) != JITTER_BUFFER_OK) {printf("Failed frozen sender resynchronize\n");
   } else {printf("Frozen sender: Jitter %d\n", out.timestamp - 100*10);
   }
   return 0;
}

测试步骤

编译 pc 端上的测试用的可执行程序

编译 pc 端的可执行程序:

gcc testdenoise.c -L /home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/build/lib -o testdenoise -I /home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/include -lm -lspeexdsp

其中:

  • gcc 前面是测试用的源文件
  • -L 后指定 so 库所在的文件夹
  • -l+so 库的名字(除去 lib 和后缀)
  • -o 前面是可执行文件的名字,
  • -l 前面是测试用的源文件要用到的头文件的门路

将编译生成的库以及测试用的可执行文件推送到开发板上

  • hdc 工具的应用 请参考用 hdc 工具在 OpenHarmony3.2 上装置利用中的相干内容
  • 获取了 ohos 源码,也能够执行 ./build.sh --product-name ohos-sdk 编译 sdk。

    • 如果有这样的编译报错,阐明依赖的库没在 linux 上装置残缺。

      • 安转残缺能力胜利编译。
      sudo apt-get update 
      sudo apt-get install binutils binutils-dev git git- lfs gnupg flex bison gperf build-essential zip 
      curl zlib1g-dev gcc-multilib g+±multilib gcc-arm-linux-gnueabi libc6-dev-i386 libc6-dev-amd64 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache libgl1-mesa-dev libxml2-utils 
      xsltproc unzip m4 bc gnutls-bin python3.8 python3-pip ruby genext2fs device-tree-compiler make 
      libffi-dev e2fsprogs pkg-config perl openssl libssl-dev libelf-dev libdwarf-dev u-boot-tools mtd-
      utils cpio doxygen liblz4-tool openjdk-8-jre gcc g++ texinfo dosfstools mtools default-jre default-
      jdk libncurses5 apt-utils wget scons python3.8-distutils tar rsync git-core libxml2-dev lib32z-dev 
      grsync xxd libglib2.0-dev libpixman-1-dev kmod jfsutils reiserfsprogs xfsprogs squashfs-tools 
      pcmciautils quota ppp libtinfo-dev libtinfo5 libncurses5-dev libncursesw5 libstdc++6 gcc-arm-none-
      eabi vim ssh locales

1. 通过与 ohos 版本匹配的 hdc_std 工具, 将编译生成的库以及测试用的可执行文件推送到开发板上

hdc_std shell               
mount -o remount,rw /        ## 从新加载零碎为可读写
mkdir speexdsp              ## 创立 speexdsp 目录寄存测试用例
exit                        ## 退出开发板零碎

2. 将压缩包 push 到开发板

hdc_std file send speexdsp.tar /speexdsp

3. 解压压缩包并将库文件拷贝到对应的目录

本次移植是基于 openharmony 规范零碎 3.2Beta1 版本,是 arm64 位零碎

hdc_std shell              ## 进入开发板零碎
cd speexdsp
tar -xvf speexdsp.tar
cp libspeexdsp_share.z.so /system/lib64/ ## 将库文件拷贝系统目录

执行测试程序、分析测试后果

分析测试后果须要应用到的音频处理软件是ocenaudio, 下载地址:https://www.ocenaudio.com/en/

①执行 testresample 可执行文件
通过剖析 testresample.c 源码可知:执行测试程序时输出一份采样率为 96000Hz 并且为单声道的音频时,通过重采样输入的音频采样率为 44100Hz。
在 pc 端运行
输出的音频为 input.pcm, 把它拷贝到 testresample 同目录下,并且新建空白文档命名为 output.pcm。

关上终端执行如下命令:

chmod 777 testresample
./testresample < input.pcm > output.pcm

应用重定向 < 符号指定输出文件、>符号指定输入文件

输入的 output.pcm 采样率变为 44100Hz,音频的 波形图 声谱图 如下:

在 rk3568 上运行

这里测试 testresample 时,将一份与 pc 端同样的 input.pcm 和 output.pcm 拷贝至开发板 speexdsp 目录。
在开发板 speexdsp 目录执行语句如下

chmod 777 testresample                  ## 增加可执行权限
./testresample < input.pcm > output.pcm

将开发板输入的 output.pcm 拷贝至 pc 端

hdc_std file recv /speexdsp/output.pcm C:\Users\jjh\Desktop\

测试后果:通过重采样,pc 端和 rk3568 开发板输入的 output.pcm 音频采样率都为 44100Hz,两者运行测试程序 testresample 后果统一。

②执行 testresample2 可执行文件

通过剖析 testresample2.c 源码可知,执行测试程序时须要指定一份空白的单声道音频文件 output.pcm。

测试 testresample2 时,须要把空白的单声道音频文件 output.pcm 拷贝至开发板 speexdsp 目录。
pc 端运行
执行语句如下:

./testresample2 > output.pcm

输入后果如下:
终端打印信息

输入音频 output.pcm 波形图和声谱图如下:

rk3568 开发板上运行
执行语句如下:

./testresample2 > output.pcm

测试后果:输入一份不为空的 output.pcm 音频文件,并且在终端输入文本如下:

1000 0 1024 22 -> 1024 0                  
1100 0 1024 24 -> 1024 15
1200 0 1024 26 -> 926 26
1300 926 1122 31 -> 1048 31
1400 950 1098 33 -> 1032 33
...
...
...
127600 1024 1024 2723 -> 1024 2723
...
...
127900 1024 1024 2729 -> 1024 2729
128000 1024 1024 2731 -> 1024 2730

以最初一行 ”128000 1024 1024 2731 -> 1024 2730“”为例, 其中 128000 为采样率(Hz);1024 为一个编码单元采样点数(帧);1024 为输出音频实践帧长;2731 为输入音频实践帧长。”->” 符号后的 1024 为通过重采样解决输出音频理论帧长,2730 为输入音频理论帧长。

  • pc 端和 rk3568 开发板运行 testresample2 可执行程序成果统一。

③执行 testecho 可执行文件

测试 testecho 时,须要输出两份音频文件,同时须要指定一份输入的音频文件。

输出的两份音频一份为 speaker.wav(麦克风收录的谈话人语音信号 + 在房间多径反射的语音),另一份为 micin.wav(麦克风收录的房间多径反射的语音)。

  • speaker.wav 失常房间环境下收录谈话人谈话声音即可,mic2.pcm 在失常环境收录时谈话人不谈话即可。
  • 同时须要指定一份 testecho_output.wav 输入文件。

执行语句如下:

./testecho speaker.wav micin.wav testecho_output.wav

测试后果:比照输出的 speaker.wav 和输入 testecho_output.wav 的波形图和声谱图,回声曾经被打消。pc 端和 rk3568 开发板运行 testecho 可执行程序成果统一。

④执行 testdenoise 可执行文件

通过剖析 testdenoise.c 源码,执行测试程序时须要指定一份输出的不为空的 8000Hz 的 input.pcm 音频,并且须要指定一份空的输入的 output.pcm 音频。

rk3568 上运行
执行语句如下:

./testdenoise < input.pcm > output.pcm 

测试后果:比照输出的 input.pcm 和输入的 outpu.pcm 的波形图和声谱图,噪声曾经被打消。pc 端和 rk3568 开发板运行 testdenoise 可执行程序成果统一。

⑤执行 testjitter 可执行文件

通过剖析 testjitter.c 源码,测试须要接管来自 udp/rtp 的网络语音数据,原生测试程序没有做到真正意义上的测试,从程序上看是通知用户如何应用接口。

执行语句如下

./testjitter

测试后果: 终端打印出语句

Frozen sender: Jitter 0

pc 端和 rk3568 开发板运行 testjitter 可执行程序成果统一。

下期预报:OAT 开源扫描和三方库上仓根本要求

退出移动版