语音调度 M0 实录:FreeSWITCH + Linphone + arm64 baresip 交叉编译上板
语音调度 M0 实录:FreeSWITCH + Linphone + arm64 baresip 交叉编译上板
目标:RK3588 板(分机 1001)与 PC 上的 Linphone(分机 1000),经 Windows 本机的 FreeSWITCH(调度服务器)注册后互拨通话。
Linphone(1000) ──┐
├── SIP 注册/信令 ──▶ FreeSWITCH @ 192.168.86.56:5070(Windows 本机)
板子 baresip(1001)─┘
- 板子:wlan0
192.168.86.131,SSHroot/rockchip - 交叉编译:Ubuntu 22.04 VM(
~/rk3588/baresip-arm64/) - FreeSWITCH 自带分机 1000–1019,密码全是
1234
通过网盘分享的文件:FreeSwitch
链接: https://pan.baidu.com/s/1jFvXV84gXkjT-xcZqLGErg?pwd=erfv 提取码: erfv
1. FreeSWITCH:管理员权限运行 + 常用命令
必须右键「以管理员身份运行」FreeSwitchConsole.exe。 原因:FS 要在 C:\Program Files\FreeSWITCH 下写 pid/日志(首次启动若报 pid 文件错误,管理员 cmd 里补目录即可,不致命):
mkdir "C:\Program Files\FreeSWITCH\run"
mkdir "C:\Program Files\FreeSWITCH\log"
防火墙放行(管理员 cmd,板子才能注册进来):
netsh advfirewall firewall add rule name="FreeSWITCH SIP" dir=in action=allow protocol=UDP localport=5070
netsh advfirewall firewall add rule name="FreeSWITCH RTP" dir=in action=allow protocol=UDP localport=16384-32768
注意:FS 是手动进程——窗口关掉 = 服务器停;优雅停止用 fs_cli -x "shutdown"。fs_cli 在安装目录下(不在 PATH),默认连本机 8021 事件口。
常用 fs_cli 命令(-x = 执行一条就退出;不带 -x 进交互控制台):
| 命令 | 用途 |
|---|---|
fs_cli -x "status" |
FS 运行状态(版本、运行时长) |
fs_cli -x "sofia status" |
SIP profile 状态;internal 行看是否 RUNNING、监听端口 |
fs_cli -x "sofia status profile internal reg" |
已注册分机列表(1000/1001 在线与否) |
fs_cli -x "show channels" |
当前通话(是否 ACTIVE、协商出的编码) |
fs_cli -x "show codecs" |
支持的编码器列表(找 opus) |
fs_cli -x "originate user/1000@192.168.86.56 &echo" |
让 FS 主动呼叫分机 1000,&echo = 回声测试 |
fs_cli -x "hupall" |
挂断所有通话(测试清场) |
fs_cli -x "reloadxml" |
重载 XML 配置(改完 dialplan/vars 后) |
fs_cli -x "shutdown" |
停止 FS |
踩坑记录:某次重启后 sofia status 报 Command not found、5070 无监听——不是配置错,是 mod_sofia 因开机 STUN 查询失败整体不加载(vars.xml 里 stun-set 查 stun.freeswitch.org 失败 → 变量空 → 模块回滚)。修复:把 vars.xml 里(约 301/314 行,搜 stun-set)两行改成固定 IP:
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=192.168.86.56"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=192.168.86.56"/>
2. 同机 5060 端口冲突 → FreeSWITCH 让位改 5070
现象:Linphone 和 FreeSWITCH 装在同一台 Windows 上,都想占 UDP 5060。更麻烦的是:Linphone 用通配地址 0.0.0.0:5060、FS 用具体地址 192.168.86.56:5060,两者能"共存绑定"但收包只命中一方——linphone 发出的 REGISTER 被投回给 linphone 自己,自己回 405,注册永远失败。
尝试 A(失败,勿再试):改 linphone 配置 %LOCALAPPDATA%\linphone\linphonerc,[sip] 段 sip_udp_port=-2 → 5062。不生效:linphone 界面/程序都不认这个键,退出时还会把 -2 写回去(实际监听端口依然是 5060)。
方案 B(成功):让 FS 挪走,linphone 保持默认 5060,所有客户端的服务器地址一律写 192.168.86.56:5070。
fs_cli -x "shutdown"
:: 管理员打开 C:\Program Files\FreeSWITCH\conf\vars.xml(先备份)
:: 第 422 行:<X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/> → 5070
:: 重启 FreeSwitchConsole.exe(管理员)
netstat -ano | findstr :5070
:: 见到 FreeSwitchConsole 监听 UDP/TCP 5070
fs_cli -x "sofia status"
:: internal 行应显示 192.168.86.56:5070
3. Linphone:用「第三方 SIP 账户」
不要"创建 Linphone 账号"(那是 sip.linphone.org 云账号),在账户里选「使用 SIP 账户」填:
| 项目 | 值 |
|---|---|
| 用户名 / SIP 地址 | 1000(sip:1000@192.168.86.56) |
| 服务器 / 域名 | 192.168.86.56:5070 |
| 传输 | UDP |
| 密码 | 1234(FS 默认分机密码) |
验证注册成功:
fs_cli -x "sofia status profile internal reg"
:: 列表里出现 1000 即成功
4. Ubuntu VM 交叉编译 arm64 baresip(删掉工作目录可全程复现)
工作目录:
~/rk3588/baresip-arm64/。工具链用 SDK 预装的 prebuilt gcc-arm-10.3(与板子 rootfs 同源)。GitHub 直连不通时下载 URL 前面加https://gh-proxy.com/前缀。
# ===== 0. 前提 =====
# 交叉工具链(SDK 自带,无需安装):
# ~/rk3588/rk3588_6.1_2025-02-26/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu
sudo apt install -y cmake # VM 只缺 cmake,其余构建工具齐全
# ===== 1. 工作区 + 环境变量 + 工具链文件 =====
mkdir -p ~/rk3588/baresip-arm64/{src,deps-src,deps}
cat > ~/rk3588/baresip-arm64/env.sh <<'EOF'
export TC=$HOME/rk3588/rk3588_6.1_2025-02-26/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu
export DEPS=$HOME/rk3588/baresip-arm64/deps
export PATH=$TC/bin:$PATH
export PKG_CONFIG_LIBDIR=$DEPS/lib/pkgconfig # 交叉编译只认自己的库,防止误用主机的
export T=$HOME/rk3588/baresip-arm64/aarch64-toolchain.cmake
EOF
cat > ~/rk3588/baresip-arm64/aarch64-toolchain.cmake <<'EOF'
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER "$ENV{TC}/bin/aarch64-none-linux-gnu-gcc")
set(CMAKE_CXX_COMPILER "$ENV{TC}/bin/aarch64-none-linux-gnu-g++")
set(CMAKE_SYSROOT "$ENV{TC}/aarch64-none-linux-gnu/libc")
set(CMAKE_FIND_ROOT_PATH "$ENV{DEPS}" "$ENV{TC}/aarch64-none-linux-gnu/libc")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_PREFIX_PATH "$ENV{DEPS}")
set(CMAKE_INSTALL_LIBDIR lib)
EOF
source ~/rk3588/baresip-arm64/env.sh # 每个新终端都要先 source(DEPS/T 为空会把文件装错地方)
# ===== 2. 三个依赖库(全部装进 $DEPS)=====
cd ~/rk3588/baresip-arm64/deps-src
# 2.1 opus 1.5.2(静态;GitHub 源码包不带 configure,走 CMake)
wget -O opus-1.5.2.tar.gz "https://gh-proxy.com/https://github.com/xiph/opus/archive/refs/tags/v1.5.2.tar.gz"
tar xf opus-1.5.2.tar.gz && cd opus-1.5.2
mkdir -p build-aarch64 && cd build-aarch64
cmake .. -DCMAKE_TOOLCHAIN_FILE=$T -DCMAKE_INSTALL_PREFIX=$DEPS \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib
make -j16 && make install
# 2.2 alsa-lib 1.2.11(和板子 rootfs 同版本,仅用于链接)
cd ~/rk3588/baresip-arm64/deps-src
wget https://www.alsa-project.org/files/pub/lib/alsa-lib-1.2.11.tar.bz2
tar xf alsa-lib-1.2.11.tar.bz2 && cd alsa-lib-1.2.11
./configure --host=aarch64-none-linux-gnu --prefix=$DEPS
make -j16 && make install
# 2.3 OpenSSL 3.5.9(静态;re 的 HMAC-SHA 没有内置实现,缺它编译必报 #error)
cd ~/rk3588/baresip-arm64/deps-src
wget -O openssl-3.5.9.tar.gz "https://gh-proxy.com/https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz"
tar xf openssl-3.5.9.tar.gz && cd openssl-3.5.9
./Configure linux-aarch64 --cross-compile-prefix=aarch64-none-linux-gnu- \
--prefix=$DEPS --openssldir=$DEPS/ssl --libdir=lib no-shared no-tests no-docs
make -j16 && make install_sw
# 检查三件套齐了:
ls $DEPS/lib/libopus.a $DEPS/lib/libasound.so $DEPS/lib/libcrypto.a $DEPS/lib/libssl.a
# ===== 3. 源码下载 =====
cd ~/rk3588/baresip-arm64/src
wget -O re-v4.12.0.tar.gz "https://gh-proxy.com/https://github.com/baresip/re/archive/refs/tags/v4.12.0.tar.gz"
wget -O baresip-v4.12.0.tar.gz "https://gh-proxy.com/https://github.com/baresip/baresip/archive/refs/tags/v4.12.0.tar.gz"
tar xf re-v4.12.0.tar.gz && tar xf baresip-v4.12.0.tar.gz
# 解出 re-4.12.0 / baresip-4.12.0;rem 不用编(re 4.12 已内置 rem,baresip 只依赖 re)
# ===== 4. 编译(顺序 re → baresip,不能反)=====
# 4.1 re(SIP 协议栈)
cd ~/rk3588/baresip-arm64/src/re-4.12.0
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$T -DCMAKE_INSTALL_PREFIX=$DEPS -DCMAKE_BUILD_TYPE=Release \
-DLIBRE_BUILD_SHARED=OFF -DOPENSSL_ROOT_DIR=$DEPS -DOPENSSL_USE_STATIC_LIBS=ON -DUSE_OPENSSL=ON
make -j16 && make install
# 4.2 baresip(STATIC=ON → 7 个模块全部打进单个二进制)
cd ~/rk3588/baresip-arm64/src/baresip-4.12.0
rm -rf build && mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=$T -DCMAKE_INSTALL_PREFIX=$DEPS -DCMAKE_BUILD_TYPE=Release \
-DSTATIC=ON -DMODULES="alsa;opus;g711;ctrl_tcp;menu;stdio;account" \
-DOPENSSL_ROOT_DIR=$DEPS -DOPENSSL_USE_STATIC_LIBS=ON \
-DRE_INCLUDE_DIR=$DEPS/include/re -DRE_LIBRARY=$DEPS/lib/libre.a
make -j16 && make install
# ===== 5. 验证 =====
file $DEPS/bin/baresip
# → ELF 64-bit LSB executable, ARM aarch64
$TC/bin/aarch64-none-linux-gnu-readelf -d $DEPS/bin/baresip | grep NEEDED
# → 只依赖 libresolv/libm/libdl/libpthread/libasound.so.2/libc —— opus、openssl 已静态内嵌
编译踩坑备忘:
- GitHub 源码包是"裸快照"没有
configure(报./configure: No such file or directory)→ opus 改走 CMake(默认就是静态库且会装 opus.pc) - re 编译报
#error missing HMAC-SHA1 backend→ 没配加密后端,这就是需要第 2.3 步 OpenSSL 的原因 - baresip cmake 找不到 re → 显式加
-DRE_INCLUDE_DIR=$DEPS/include/re -DRE_LIBRARY=$DEPS/lib/libre.a account模块必须编(不编 = 不读 accounts 文件 = 永远不注册);menu;stdio提供板端交互控制台-DMODULES改了就把build/删掉重来(rm -rf build)最省心
上板部署(VM → Windows 中转 → 板子):
# Windows 上执行:
scp rkvm:~/rk3588/baresip-arm64/deps/bin/baresip C:\VMShare\baresip
scp C:\VMShare\baresip root@192.168.86.131:/root/baresip
# 板端:
chmod +x /root/baresip
板端 /root/.baresip/config(首次启动 baresip 会自动生成目录,然后改成这样):
sip_listen 0.0.0.0:5060
audio_player alsa,default
audio_source alsa,default
audio_alert alsa,default
ctrl_tcp_listen 127.0.0.1:4444
module stdio.so
module alsa.so
module g711.so
module opus.so
module ctrl_tcp.so
module_app account.so
module_app menu.so
板端 /root/.baresip/accounts(一行):
<sip:1001@192.168.86.56:5070>;auth_user=1001;auth_pass=1234
启动 /root/baresip,看到 All 1 useragent registered successfully! 即注册成功(音频三行随后按第 5 节改成 plughw:0,0)。
5. 板端刷屏 "Resume failed" → 停 pulseaudio + plughw 直连
现象:板端 /dial 9196 0 后被日志刷屏:
W: [alsa-source-dailink-multicodecs ES8323 HiFi-0] alsa-source.c: Resume failed, couldn't restore original sample settings.
根因:刷屏的不是 baresip,是板上的 pulseaudio 守护进程——它抢占了 ES8323 声卡,恢复采集采样规格失败后反复重试打印此警告;同时 pulse 占着声卡,baresip 走 default 设备也采不到音频(回声必空)。正确做法:停掉 pulse,让 baresip 直连声卡。
# 1) baresip 里按 b 挂断(刷屏不停也没关系),再按 q 退出
# 2) 停 pulseaudio
ps w | grep -i pulse
killall pulseaudio # 没有 killall 就用 kill $(pidof pulseaudio)
ps w | grep -i pulse # 应该查不到了
# 3) 找 ES8323 声卡编号(看名字里带 ES8323 那张,大概率 0)
cat /proc/asound/cards
# 4) 看当前音频配置行
grep -n 'audio_source\|audio_player\|audio_alert' /root/.baresip/config
# 5) 三行都改成直连 hw(把 0,0 换成上一步看到的 卡号,0)
sed -i 's|^audio_source.*|audio_source alsa,plughw:0,0|; s|^audio_player.*|audio_player alsa,plughw:0,0|; s|^audio_alert.*|audio_alert alsa,plughw:0,0|' /root/.baresip/config
grep -n 'audio_source\|audio_player\|audio_alert' /root/.baresip/config
# 6) 重开 baresip
./baresip
# 等到 "All 1 useragent registered successfully!"
/dial 9196 0
# 对板子说话,应该能听到自己的回声,且控制台不再刷屏
补充:
- 不想改配置:baresip 运行中直接敲
/ausrc alsa,plughw:0,0和/auplay alsa,plughw:0,0(对之后的通话生效) - 杀 pulse 只对本次生效,板子重启后会再起(长期方案在 M1 阶段收口)
- 回声通过后:
/dial 1000 0打给 linphone;linphone 反向拨 1001,板端按a接听
附:baresip 控制台速查
- 长命令必须以
/开头(不带/,首字符会被当快捷键吞掉):/dial <目标> <账号序号> - 例:
/dial 9196 0(FS 回声测试号)、/dial 1000 0(打给 linphone;0= 第一个账号) - 快捷键:
a接听、b挂断、q退出、r查注册状态
M0 验收进度:注册 ✓(板端 1001 ↔ FS 5070);拨号链路 ✓(9196 回声通话已建立,编码 PCMU);双向有声 ↔ linphone ——待音频复测。
浙公网安备 33010602011771号