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


    正文

    然而本次优化仍然没能用上整套VoE,因为VoE不仅仅包含音频预处理,它将音频编码模块、传输模块一并融入了引擎,而项目需要使用既有的编码、传输层,因此使用整个VoE对我来说显得冗余且不可操作。天无绝人之路,抛开VoE不谈,找到了仅次于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基础步骤及部分要点

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

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

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

    下面我们逐步进行分解:

    step 3.1

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

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

    其中 APP_STL 的官方说明如下:

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

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

    本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓

    step 3.2

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

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

    step 3.3

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

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

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

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

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

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

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

    总结

    整个编译工作在现在看来非常简单,但需要很多的耐心和搜索,不过结果还是令人比较满意的,APM出来的效果比之前自己单独使用各个音频模块要好很多。不过对于抖动等因素的影响,APM就力不从心了。

     本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击领取↓↓

  • 相关阅读:
    【强化学习论文合集】ICLR-2021 强化学习论文
    vscode中提升效率的插件扩展——待更新
    [NCTF2019]SQLi-1||SQL注入
    大模型时代的具身智能系列专题(六)
    springmvc请求转发和重定向的四种跳转方式
    Mysql的时间类型选定:Datetime,Timestamp,Bigint
    Craig Federighi 和 John Giannandrea 在 WWDC 上谈论苹果智能技术
    JMeter 如何实现 Elasticsearch 8.X 性能测试?
    数据离散化
    中国剩余定理算法的实现
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/126389659