前言

在写【单独编译使用WebRTC的音频处理模块 - android】一文之前,就一直想直接把WebRTC的音频处理引擎VoE整个儿编译出来供自己的项目使用,但限于技术拙劣、时间紧迫,所以没能成功。只得挨个挨个把引擎中的Aecm、Agc、Ns以及Vad模块单独编译出来凑合着用。虽能达到一定效果,但始终不甚理想。5个月后,bill需要优化之前的项目,于是就下了狠心,定要将整个音频处理模块用上 ...

正文

然而本次优化仍然没能用上整套VoE,因为VoE不仅仅包含音频预处理,它将音频编码模块、传输模块一并融入了引擎,而bill的项目需要使用既有的编码、传输层,因此使用整个VoE对我来说显得冗余且不可操作。天无绝人之路,抛开VoE不谈,bill找到了仅次于VoE层级的模块 —— APM(Audio Preprocessing Module) —— 一个整合了前文所有模块且纯粹的音频预处理单元。

Step 1 - 下载Google WebRTC源码

Google WebRTC的开发进度还是可观的,本文将以WebRTC的最新trunk revision 5125为例进行讲解。请自行使用SVN同步以下目录(至于同步的方法,请自行google):

http://webrtc.googlecode.com/svn/trunk/

 

Step 2 - 提取编译APM所需资源

APM的整体编译需要WebRTC源码目录下的如下资源:

1)common_audio 整个目录

2)modules 目录(不包含 video 部分)

3)system_wrappers 整个目录

4)位于 WebRTC 源码根目录下的 common_types.h | common.h | typedefs.h 三个头文件。

5)位于 WebRTC 主目录下的 android-webrtc.mk 文件。

Step 3 - 在Eclipse中编译APM基础步骤及部分要点

对于Eclipse中jni的编译及使用请参见上篇文章所述,在此不再赘述。

此节仅按照自己的jni目录组织结构进行讲解,读者可根据自己需要进行调整。

在Eclipse中的jni组织结构如下:

Step-2中的所有文件夹及头文件均位于 webrtc 子目录下。android-webrtc.mk 位于 jni 根目录下。

下面我们逐步进行分解:

step 3.1

首先我们需要对整个 android 工程进行描述和设定,打开 jni 根目录下的 Application.mk 文件,编辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
# Copyright (c) 2013 BillHoo. All Rights Reserved.
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS.  All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-9

其中 APP_STL 的官方说明如下:

1
2
3
4
5
6
7
8
9
10
11
APP_STL
    By default, the NDK build system provides C++ headers for the minimal
    C++ runtime library (/system/lib/libstdc++.so) provided by the Android
    system.
    However, the NDK comes with alternative C++ implementations that you can
    use or link to in your own applications. Define APP_STL to select one of
    them. Examples are:
       APP_STL := stlport_static    --> static STLport library
       APP_STL := stlport_shared    --> shared STLport library
       APP_STL := system            --> default C++ runtime library
    For more information on the subject, please read docs/CPLUSPLUS-SUPPORT.html

由于 NDK 默认使用最小 C++ 运行时库进行项目的编译,导致无法编译 WebRTC 中使用诸如 std::map 等 STL 容器的源码。因此我们需要自行设定适合本项目的 C++ 运行时库 gnustl_static。

step 3.2

打开并编辑 jni 根目录下的 Android.mk 文件如下,本文件只需告诉 NDK 去调用所有子目录下的 Android.mk 文件即可:

1
2
3
4
5
6
7
8
9
# Copyright (c) 2013 BillHoo. All Rights Reserved.
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS.  All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
include $(call all-subdir-makefiles)

step 3.3

准备工作就绪,下面就可以开始着手编译整个 APM 单元了,首先打开 jni/webrtc 目录,新建 Android.mk 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Copyright (c) 2013 BillHoo. All Rights Reserved.
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS.  All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
#
MY_WEBRTC_ROOT_PATH := $(call my-dir)
#
# voice
include $(MY_WEBRTC_ROOT_PATH)/common_audio/signal_processing/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/common_audio/vad/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/aec/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/aecm/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/agc/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/ns/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_processing/utility/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/utility/source/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/modules/audio_device/Android.mk
include $(MY_WEBRTC_ROOT_PATH)/system_wrappers/source/Android.mk
#
# build .so
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
LOCAL_MODULE := liblu_audio_preprocessing
LOCAL_MODULE_TAGS := optional
LOCAL_WHOLE_STATIC_LIBRARIES := \
    libwebrtc_spl \
    libwebrtc_apm \
    libwebrtc_apm_utility \
    libwebrtc_vad \
    libwebrtc_ns \
    libwebrtc_agc \
    libwebrtc_aec \
    libwebrtc_aecm \
    libwebrtc_system_wrappers \
    libwebrtc_audio_device \
    libwebrtc_utility
#
# Add Neon libraries.
ifeq ($(WEBRTC_BUILD_NEON_LIBS),true)
LOCAL_WHOLE_STATIC_LIBRARIES += \
    libwebrtc_aecm_neon \
    libwebrtc_ns_neon \
    libwebrtc_spl_neon
endif
LOCAL_STATIC_LIBRARIES := \
    libprotobuf-cpp-2.3.0-lite
LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libdl \
    libstlport
LOCAL_PRELINK_MODULE := false
#
#TODO(billhoo) find a properway to do this.
LOCAL_LDLIBS += $(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/libgnustl_static.a
LOCAL_LDLIBS += -lOpenSLES
ifndef NDK_ROOT
include external/stlport/libstlport.mk
endif
include $(BUILD_SHARED_LIBRARY)

需要注意的几点:

1)在编译时如提示找不到 ../../../Android.mk 文件等错误,请检查并修正你的相对路径。

2)位于第60行的gnu静态库链接路径是针对NDK版本 r8d 的,如读者版本不匹配,请自行找到 libgnustl_static.a 静态库的路径进行替换。

3)本示例并不打算编译 WebRTC 的测试工程,请使用 Eclipse 搜索文件功能,找到 Android.mk 文件中的 -DWEBRTC_AUDIOPROC_DEBUG_DUMP 并注释掉。

step 3.4

万事俱备,我们可以开始编译 APM 了,不过在编译过程中肯定还会有很多小问题出现(比如相对路径不正确、找不到某某函数的符号等等),这些问题就留给读者自行google、SO解决了,bill就不再赘述。

Step 4 - 在android应用中使用APM的注意事项

经过上述步骤,读者便能够得到 libwebrtc_audio_preprocessing.so 这个动态链接库。我们需要做的仅仅是编写自己的 jni 包装函数向 android 应用层提供 APM 的接口。具体做法bill之前的文章已经详细介绍过。这里需要注意的是,如果读者打算在自己的动态库中引用已经编译好的 APM 库,那么在 android 类加载这两个库时的顺序是敏感的。

假设读者将自己的 JNI 接口封装成单独的库 libmy_jni_wrapper.so,而该库引用了 libwebrtc_audio_preprocessing.so,那么在加载这两个库时应该参照如下顺序:

1
2
3
4
5
static {
    // Ordering of loading these shared libraries is significant.
    System.loadLibrary("webrtc_audio_preprocessing");
    System.loadLibrary("my_jni_wrapper");
}

若顺序写反,在运行时将得到找不到 webrtc_audio_preprocessing 库中符号的异常。

总结

整个编译工作在现在看来非常简单,但需要很多的耐心和搜索,不过结果还是令人比较满意的,APM出来的效果比之前自己单独使用各个音频模块要好很多。不过对于抖动等因素的影响,APM就力不从心了。也许bill接下来该花时间去看看NetEq、Jitter Buffer等模块了。如何使用他们,如何融进自己的项目,到时候就知道了。

【WebRTC音频预处理单元APM的整体编译及使用 - android】的更多相关文章

  1. WebRTC音频预处理单元APM的整体编译及使用

    正文 行的gnu静态库链接路径是针对NDK版本 r8d 的,如读者版本不匹配,请自行找到 libgnustl_static.a 静态库的路径进行替换. 3)本示例并不打算编译 WebRTC 的测试工程 ...

  2. webrtc的音频处理模块apm( audio processing)下载与编译出libwebrtc_audio_preprocessing.so

    webrtc代码在android和chromium项目中都有.但是android中的那个带有Android.mk,稍微修改下就能用ndk-build编译出libwebrtc_audio_preproc ...

  3. 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...

  4. 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)

    webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...

  5. 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...

  6. C预编译, 预处理, C/C++头文件, 编译控制,

    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...

  7. WebRTC音视频引擎研究(1)--整体架构分析

    WebRTC技术交流群:234795279 原文地址:http://blog.csdn.net/temotemo/article/details/7530504     1.WebRTC目的     ...

  8. 转: WebRTC音视频引擎研究(1)--整体架构分析

    转自: http://blog.csdn.net/temotemo/article/details/7530504   目录(?)[+]   WebRTC技术交流群:234795279 原文地址:ht ...

  9. 音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

    前言: 前面我用了很多章实现了javaCV的基本操作,包括:音视频捕捉(摄像头视频捕捉和话筒音频捕捉),推流(本地音视频或者摄像头话筒混合推流到服务器),转流(rtsp->rtmp),收流(录制 ...

随机推荐

  1. [luoguP2736] “破锣摇滚”乐队 Raucous Rockers(DP)

    传送门 f[i][j]表示前i首歌放到前j个盘里最多能放多首 ntr[i][j]表示i~j中最多能放进一张盘中多少首歌 ntr数组可以贪心预处理出来. #include <cstdio> ...

  2. jQuery的切换函数(hover,toggle)

    1.hover:(鼠标悬停与离开事件) 一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法.这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态. 当鼠标移动到一个匹配的 ...

  3. Android基本动画

    Android基本动画 Android Animations动画使用详解 一.动画类型 Android的animation由四种类型组成:alpha.scale.translate.rotate XM ...

  4. HDU 1896 【留个使用priority_queue容器的样例】

    感谢<啊哈!算法>的讲解,水鸟弄懂了什么是优先队列. 题意是:在路上有很多石子,给出他们的初始位置和小明能够将他们扔出的距离,当小明遇到奇数个石子的时候就会把它扔出,遇到偶数个就会忽略他, ...

  5. Wannafly挑战赛4

    A(枚举) =w= B(枚举) 分析: 枚举每一位,考虑每位贡献,就是相当于在一段区间内找有多少1在奇数位上,有多少个1在偶数位上,维护一下各自前缀和就行了 时间复杂度O(32n) C(签到) D(d ...

  6. Spring Boot使用Feign客户端调用远程服务时出现:timed-out and no fallback available,failed and no fallback available的问题解决

    timed-out and no fallback available: 这个错误基本是出现在Hystrix熔断器,熔断器的作用是判断该服务能不能通,如果通了就不管了,调用在指定时间内超时时,就会通过 ...

  7. 【stl学习笔记】红黑树

    转自维基百科 红黑树是一种平衡二叉搜索树,它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目. 性质: 红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色.在二叉查找 ...

  8. 【python】对象和面向对象

    类的定义 python支持多重继承,在类名后面的小括号中,可以列出多个类名,以逗号分割. __init__方法在类的实例创建后被立即调用,注意与c++中构造函数不一样,因为对象在调用__init__时 ...

  9. 用CSS画小猪佩奇,你就是下一个社会人! js将“I am a coder”反转成 “coder a am I”,不许用split,join,subString,reverse;求解方法三

    用CSS画小猪佩奇,你就是下一个社会人!   欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:江志耿 | 腾讯TEG网络工程师 我是佩奇,哼,这是我的弟弟乔治,呱呱,这是我的妈妈,嚯 ...

  10. 搜索学术论文訪问google的能用的几个IP地址

    google搜索引擎打不开时的解决的方法,谷歌(google)的IP是多少? google IP镜像. 这里搜集了几个经过測试可用的IP,用来在不能域名訪问google的时候进行訪问 更新一个最新的. ...