构建arm32位安卓7的PJSIP

📘 使用 Ubuntu Docker 构建 PJSIP + OpenSSL + Oboe Android 原生库的完整流程

本指南适用于开发者在 Ubuntu 22.04 环境下,使用 Docker 容器构建适用于 Android 平台的原生通信库 —— PJSIP,并集成第三方依赖如 OpenSSL(用于安全通信)和 Oboe(用于高性能音频处理)。该流程尤其适用于:

  • 需要为旧设备(如 armv7)构建兼容库的场景;
  • 使用 Android NDK 构建 .so 动态库;
  • 将构建好的库嵌入到 Android 应用中(如 VoIP 或音频通话 APP);
  • 避免在本地环境安装过多依赖,优先在干净的容器中构建。

主要内容包括:

  • 配置 Ubuntu 镜像源,加速构建;
  • 安装构建依赖(如 SWIG、NDK、make);
  • 下载并构建 OpenSSL 和 Oboe;
  • 配置并编译 PJSIP(推荐使用 2.14.1 版本);
  • 最后复制所需 .so 库到 Android 项目目录中,供应用打包使用。

主要参考的官方文档:

🔧 环境初始化:基于 Ubuntu 22.04 Docker 容器

docker run -it ubuntu:22.04 /bin/bash

更新 apt 源为华为云镜像

cp -a /etc/apt/sources.list /etc/apt/sources.list.bak
sed -i "s@http://.*archive.ubuntu.com@http://mirrors.huaweicloud.com@g" /etc/apt/sources.list
sed -i "s@http://.*security.ubuntu.com@http://mirrors.huaweicloud.com@g" /etc/apt/sources.list

📦 安装基本构建工具和依赖

apt update
apt install -y swig wget unzip make perl-modules

验证 SWIG 安装:

swig -version

📁 下载并配置依赖库

下载并配置 Android NDK r28c

cd /usr/src/
wget https://googledownloads.cn/android/repository/android-ndk-r28c-linux.zip
unzip android-ndk-r28c-linux.zip
export ANDROID_NDK_ROOT=/usr/src/android-ndk-r28c
export PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$ANDROID_NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH

下载 Oboe(低延迟音频库)

cd /usr/src/
wget https://github.com/google/oboe/releases/download/1.9.3/oboe-1.9.3.aar
unzip oboe-1.9.3.aar -d oboe/
export OBOE_DIR=/usr/src/oboe

🔐 编译 OpenSSL(静态链接)

解压和构建

cd /usr/src/
tar -xzf openssl-3.4.2.tar.gz
cd openssl-3.4.2
./Configure android-arm64 -D__ANDROID_API__=29
make

拷贝编译结果到 lib/

mkdir lib
cp lib*.a lib/
export OPENSSL_DIR=/usr/src/openssl-3.4.2

📦 编译 PJSIP(2.14.1 推荐版本)

说明:2.15 版本过新,兼容性差。建议使用 2.14.1,对旧设备支持更好。

清理旧构建结果

cd /usr/src/pjproject-2.14.1
make distclean

配置构建参数

TARGET_ABI=armeabi-v7a APP_PLATFORM=android-7 ./configure-android --use-ndk-cflags --with-ssl=$OPENSSL_DIR --with-oboe=$OBOE_DIR
# 如果其实这里可能应该写成 android-24
# Android 4.4   APP_PLATFORM=android-19
# Android 5.0   APP_PLATFORM=android-21
# Android 6.0   APP_PLATFORM=android-23
# Android 7.0 APP_PLATFORM=android-24
# Android 9.0   APP_PLATFORM=android-28

配置 Java 环境(Java 8)

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

编译

make dep && make clean && make

🧪 构建 Java Bindings

清理并编译 SWIG Java 绑定

cd pjsip-apps/src/swig
make

📂 复制第三方库到 Android 项目中

设置架构变量(根据需要设置,例如 arm64-v8a、armeabi-v7a、x86_64)

export ARCH=armeabi-v7a
cd pjsip-apps/src/swig/java/android/pjsua2/src/main/jniLibs/$ARCH

复制 OpenSSL .so 动态库

cp -v $OPENSSL_DIR/*.so .
# 示例输出:
# '/usr/src/openssl-3.4.2/libcrypto.so' -> './libcrypto.so'
# '/usr/src/openssl-3.4.2/libssl.so' -> './libssl.so'

复制 Oboe .so 动态库

cp -v $OBOE_DIR/prefab/modules/oboe/libs/android.$ARCH/*.so .
# 示例输出:
# '/usr/src/oboe/prefab/modules/oboe/libs/android.armeabi-v7a/liboboe.so' -> './liboboe.so'

其他说明

关于 2.15.1 在旧机运行碰到的错误

2025-07-14 15:40:09.384 17758-17758 AndroidRuntime          org.pjsip.pjsua2.app                 D  Shutting down VM
2025-07-14 15:40:09.384 17758-17758 AndroidRuntime          org.pjsip.pjsua2.app                 E  FATAL EXCEPTION: main
    Process: org.pjsip.pjsua2.app, PID: 17758
    java.lang.UnsatisfiedLinkError: No implementation found for void org.pjsip.pjsua2.pjsua2JNI.swig_module_init() (tried Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init and Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init__)
        at org.pjsip.pjsua2.pjsua2JNI.swig_module_init(Native Method)
        at org.pjsip.pjsua2.pjsua2JNI.<clinit>(pjsua2JNI.java:3008)
        at org.pjsip.pjsua2.pjsua2JNI.new_Endpoint(Native Method)
        at org.pjsip.pjsua2.Endpoint.<init>(Endpoint.java:80)
        at org.pjsip.pjsua2.app.MyApp.<clinit>(MyApp.java:319)
        at org.pjsip.pjsua2.app.MainActivity.onCreate(MainActivity.java:159)
        at android.app.Activity.performCreate(Activity.java:6711)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6141)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
2025-07-14 15:40:09.387 17758-17758 Process                 org.pjsip.pjsua2.app                 I  Sending signal. PID: 17758 SIG: 9
2025-07-14 15:40:09.450 17778-17778 art                     org.pjsip.pjsua2.app                 I  Late-enabling -Xcheck:jni
2025-07-14 15:40:09.523 17778-17789 art                     org.pjsip.pjsua2.app                 E  wxl--suspend all.
2025-07-14 15:40:09.569 17778-17778 System.err              org.pjsip.pjsua2.app                 W  Failed to load native library pjsua2
2025-07-14 15:40:09.569 17778-17778 System.err              org.pjsip.pjsua2.app                 W  java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__sendto_chk" referenced by "/data/app/org.pjsip.pjsua2.app-1/base.apk!/lib/armeabi-v7a/libpjsua2.so"...
2025-07-14 15:40:09.570 17778-17778 art                     org.pjsip.pjsua2.app                 E  No implementation found for void org.pjsip.pjsua2.pjsua2JNI.swig_module_init() (tried Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init and Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init__)
2025-07-14 15:40:09.570 17778-17778 AndroidRuntime          org.pjsip.pjsua2.app                 D  Shutting down VM

核心错误是 cannot locate symbol "__sendto_chk" referenced by "/data/app/org.pjsip.pjsua2.app-1/base.apk!/lib/armeabi-v7a/libpjsua2.so"

我是直接用 APP_PLATFORM=android-7 ./configure-android 来指定低版本,从而解决这个不认识高版本符号的问题。

(具体是否可以有别的方法能够在高版本中编译出兼容低版本的库文件,我还没做进一步探索尝试。)

但是引来了下面的问题。

关于 2.15.1 使用 android-7 make 失败的问题

由于前面的问题,我要使用Android-7,但是马上就碰到 make 失败。

/usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -Wall -DPJ_AUTOCONF=1  -target armv7-none-linux-androideabi21 -fdata-sections -ffunction-sections -funwind-tables -no-canonical-prefixes --sysroot /usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/sysroot -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -D_FORTIFY_SOURCE=2 -fpic -mthumb -Ijni -DANDROID -Wformat -Werror=format-security   -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1 -I/usr/src/openssl-3.4.2/include         -DPJMEDIA_VIDEO_DEV_HAS_ANDROID_OPENGL=1 -DPJMEDIA_VIDEO_DEV_HAS_ANDROID=1   -DPJMEDIA_AUDIO_DEV_HAS_OBOE=1 -I/usr/src/oboe/prefab/modules/oboe/include -I/usr/src/pjproject-2.15.1/third_party/build/speex -I/usr/src/pjproject-2.15.1/third_party/speex/include -DPJMEDIA_HAS_OPENCORE_AMRNB_CODEC=0 -DPJMEDIA_HAS_OPENCORE_AMRWB_CODEC=0 -DPJMEDIA_HAS_LYRA_CODEC=0 -I/usr/src/pjproject-2.15.1/third_party/build/srtp -I/usr/src/pjproject-2.15.1/third_party/srtp/crypto/include -I/usr/src/pjproject-2.15.1/third_party/srtp/include -DPJMEDIA_RESAMPLE_IMP=PJMEDIA_RESAMPLE_LIBRESAMPLE -DPJMEDIA_HAS_LIBYUV=1 -I/usr/src/pjproject-2.15.1/third_party/yuv/include -DPJMEDIA_HAS_WEBRTC_AEC=1 -I/usr/src/pjproject-2.15.1/third_party/webrtc/src -DPJMEDIA_HAS_WEBRTC_AEC3=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0 -I../include -I../../pjlib/include -I../../pjlib-util/include -I../../pjmedia/include -I../../pjnath/include -I../..     -I/usr/src/pjproject-2.15.1/third_party \
        -c -o output/pjmedia-codec-armv7-unknown-linux-android/g722/g722_dec.o \
        ../src/pjmedia-codec/g722/g722_dec.c
/usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -Wall -DPJ_AUTOCONF=1  -target armv7-none-linux-androideabi21 -fdata-sections -ffunction-sections -funwind-tables -no-canonical-prefixes --sysroot /usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/sysroot -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -D_FORTIFY_SOURCE=2 -fpic -mthumb -Ijni -DANDROID -Wformat -Werror=format-security   -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1 -I/usr/src/openssl-3.4.2/include         -DPJMEDIA_VIDEO_DEV_HAS_ANDROID_OPENGL=1 -DPJMEDIA_VIDEO_DEV_HAS_ANDROID=1   -DPJMEDIA_AUDIO_DEV_HAS_OBOE=1 -I/usr/src/oboe/prefab/modules/oboe/include -I/usr/src/pjproject-2.15.1/third_party/build/speex -I/usr/src/pjproject-2.15.1/third_party/speex/include -DPJMEDIA_HAS_OPENCORE_AMRNB_CODEC=0 -DPJMEDIA_HAS_OPENCORE_AMRWB_CODEC=0 -DPJMEDIA_HAS_LYRA_CODEC=0 -I/usr/src/pjproject-2.15.1/third_party/build/srtp -I/usr/src/pjproject-2.15.1/third_party/srtp/crypto/include -I/usr/src/pjproject-2.15.1/third_party/srtp/include -DPJMEDIA_RESAMPLE_IMP=PJMEDIA_RESAMPLE_LIBRESAMPLE -DPJMEDIA_HAS_LIBYUV=1 -I/usr/src/pjproject-2.15.1/third_party/yuv/include -DPJMEDIA_HAS_WEBRTC_AEC=1 -I/usr/src/pjproject-2.15.1/third_party/webrtc/src -DPJMEDIA_HAS_WEBRTC_AEC3=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0 -I../include -I../../pjlib/include -I../../pjlib-util/include -I../../pjmedia/include -I../../pjnath/include -I../..     -I/usr/src/pjproject-2.15.1/third_party \
        -c -o output/pjmedia-codec-armv7-unknown-linux-android/g7221.o \
        ../src/pjmedia-codec/g7221.c
/usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++  -DPJ_AUTOCONF=1     -Wall -DPJ_AUTOCONF=1  -target armv7-none-linux-androideabi21 -fdata-sections -ffunction-sections -funwind-tables -no-canonical-prefixes --sysroot /usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/sysroot -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -D_FORTIFY_SOURCE=2 -fpic -mthumb -Ijni -DANDROID -Wformat -Werror=format-security   -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1 -I/usr/src/openssl-3.4.2/include         -DPJMEDIA_VIDEO_DEV_HAS_ANDROID_OPENGL=1 -DPJMEDIA_VIDEO_DEV_HAS_ANDROID=1   -DPJMEDIA_AUDIO_DEV_HAS_OBOE=1 -I/usr/src/oboe/prefab/modules/oboe/include -I/usr/src/pjproject-2.15.1/third_party/build/speex -I/usr/src/pjproject-2.15.1/third_party/speex/include -DPJMEDIA_HAS_OPENCORE_AMRNB_CODEC=0 -DPJMEDIA_HAS_OPENCORE_AMRWB_CODEC=0 -DPJMEDIA_HAS_LYRA_CODEC=0 -I/usr/src/pjproject-2.15.1/third_party/build/srtp -I/usr/src/pjproject-2.15.1/third_party/srtp/crypto/include -I/usr/src/pjproject-2.15.1/third_party/srtp/include -DPJMEDIA_RESAMPLE_IMP=PJMEDIA_RESAMPLE_LIBRESAMPLE -DPJMEDIA_HAS_LIBYUV=1 -I/usr/src/pjproject-2.15.1/third_party/yuv/include -DPJMEDIA_HAS_WEBRTC_AEC=1 -I/usr/src/pjproject-2.15.1/third_party/webrtc/src -DPJMEDIA_HAS_WEBRTC_AEC3=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0 -I../include -I../../pjlib/include -I../../pjlib-util/include -I../../pjmedia/include -I../../pjnath/include -I../..      -I/usr/src/pjproject-2.15.1/third_party \
        -c -o output/pjmedia-codec-armv7-unknown-linux-android/and_aud_mediacodec.o \
        ../src/pjmedia-codec/and_aud_mediacodec.cpp
../src/pjmedia-codec/and_aud_mediacodec.cpp:1096:5: error: 'AMediaCodec_setAsyncNotifyCallback' is unavailable: introduced in Android 28
 1096 |     AMediaCodec_setAsyncNotifyCallback(codec_data->enc, async_cb, codec_data);
      |     ^
/usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/media/NdkMediaCodec.h:499:16: note: 'AMediaCodec_setAsyncNotifyCallback' has been explicitly marked unavailable here
  499 | media_status_t AMediaCodec_setAsyncNotifyCallback(
      |                ^
../src/pjmedia-codec/and_aud_mediacodec.cpp:1097:5: error: 'AMediaCodec_setAsyncNotifyCallback' is unavailable: introduced in Android 28
 1097 |     AMediaCodec_setAsyncNotifyCallback(codec_data->dec, async_cb, codec_data);
      |     ^
/usr/src/android-ndk-r28c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/media/NdkMediaCodec.h:499:16: note: 'AMediaCodec_setAsyncNotifyCallback' has been explicitly marked unavailable here
  499 | media_status_t AMediaCodec_setAsyncNotifyCallback(
      |                ^
2 errors generated.
make[2]: *** [/usr/src/pjproject-2.15.1/build/rules.mak:178: output/pjmedia-codec-armv7-unknown-linux-android/and_aud_mediacodec.o] Error 1
make[2]: Leaving directory '/usr/src/pjproject-2.15.1/pjmedia/build'
make[1]: *** [Makefile:222: libpjmedia-codec-armv7-unknown-linux-android.a] Error 2
make[1]: Leaving directory '/usr/src/pjproject-2.15.1/pjmedia/build'
make: *** [Makefile:14: all] Error 1

大概就是因为里面有个方法 AMediaCodec_setAsyncNotifyCallback 要求用 android 28,我指定的安卓平台版本太低了。
于是我查了下源码的提交日志,发现 2.15 才新引入该方法,所以,我就改到 2.14.1 了。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇