AlmaLinux 9 编译安装 FreeSWITCH 1.10.12 与 mod_audio_fork
这篇记录 AlmaLinux 9 上编译安装 FreeSWITCH 1.10.12 的脚本。
和 Debian 12 版本相比,这个脚本更像线上安装脚本:它会检查系统版本、启用 CRB/EPEL、 固定依赖源码版本、编译 mod_audio_fork,最后还会验证关键二进制和模块是否存在。
环境与目标 验证环境:
1 Linux localhost.localdomain 5.14.0-687.5.3.el9_8.x86_64 x86_64 GNU/Linux
安装目标:
1 2 3 4 FS_VERSION="v1.10.12" INSTALL_PATH="/usr/local/freeswitch" SRC_ROOT="/usr/src" DEPS_ROOT="/usr/src/freeswitch-deps"
最终安装:
FreeSWITCH 1.10.12
libks
sofia-sip
spandsp
signalwire-c
mod_audio_fork
mod_sofia、mod_spandsp、mod_shout、mod_mariadb
安装脚本 新建 freeswitch_install.sh:
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 #!/bin/bash set -euo pipefailFS_VERSION="v1.10.12" INSTALL_PATH="/usr/local/freeswitch" SRC_ROOT="/usr/src" DEPS_ROOT="/usr/src/freeswitch-deps" JOBS="${JOBS:-$(nproc)} " PKG_CONFIG_PATH_VALUE="/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig" log () { echo ">>> $*" ; }fail () { echo "ERROR: $*" >&2; exit 1; }require_root () { if [ "$(id -u) " -ne 0 ]; then fail "请以 root 用户执行该脚本" fi } ensure_almalinux9 () { if [ ! -r /etc/os-release ]; then fail "无法读取 /etc/os-release" fi . /etc/os-release if [ "${ID:-} " != "almalinux" ] || [[ "${VERSION_ID:-} " != 9* ]]; then fail "该脚本仅支持 AlmaLinux 9,当前系统: ${PRETTY_NAME:-unknown} " fi } install_packages () { log "启用 AlmaLinux CRB 与 EPEL 仓库" dnf -y install dnf-plugins-core epel-release dnf config-manager --set-enabled crb dnf -y makecache log "安装 FreeSWITCH 与 mod_audio_fork 构建依赖" dnf -y install \ autoconf automake bison boost-devel bzip2 cmake curl expat-devel \ flac-devel gcc gcc-c++ gdbm-devel git json-c-devel libatomic \ lame-devel ldns-devel libcurl-devel libdb-devel libedit-devel \ libjpeg-turbo-devel libogg-devel libshout-devel libsndfile-devel \ libtiff-devel libtool libuuid-devel libvorbis-devel libwebsockets-devel \ lua-devel make mariadb-connector-c-devel mpg123-devel nasm ncurses-devel \ openssl-devel opus-devel patch pcre-devel pcre2-devel perl \ pkgconf-pkg-config postgresql-devel python3-devel speex-devel \ speexdsp-devel sqlite-devel tar unixODBC-devel wget which yasm zlib-devel } clone_deps () { log "准备依赖源码目录: ${DEPS_ROOT} " rm -rf "${DEPS_ROOT} " mkdir -p "${DEPS_ROOT} " cd "${DEPS_ROOT} " git clone --depth 1 --branch v2.0.10 https://github.com/signalwire/libks.git git clone --depth 1 --branch v1.13.17 https://github.com/freeswitch/sofia-sip.git git clone --depth 1 --branch fs https://github.com/freeswitch/spandsp.git git clone --depth 1 --branch v2.0.5 https://github.com/signalwire/signalwire-c.git git clone --depth 1 https://github.com/Wangijun/mod_audio_fork.git } build_libks () { log "编译安装 libks" cd "${DEPS_ROOT} /libks" cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib64 \ -DWITH_LIBBACKTRACE=0 cmake --build build --parallel "${JOBS} " touch build/copyright cmake --install build ldconfig } build_sofia () { log "编译安装 Sofia-SIP" cd "${DEPS_ROOT} /sofia-sip" ./bootstrap.sh ./configure --prefix=/usr --libdir=/usr/lib64 make -j"${JOBS} " make install ldconfig } build_spandsp () { log "编译安装 SpanDSP" cd "${DEPS_ROOT} /spandsp" ./bootstrap.sh ./configure --prefix=/usr --libdir=/usr/lib64 make -j"${JOBS} " make install ldconfig } build_signalwire_c () { log "编译安装 signalwire-c" cd "${DEPS_ROOT} /signalwire-c" export PKG_CONFIG_PATH="${PKG_CONFIG_PATH_VALUE} " cmake -S . -B build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib64 cmake --build build --parallel "${JOBS} " touch build/copyright cmake --install build ldconfig } clone_freeswitch () { log "下载 FreeSWITCH ${FS_VERSION} " cd "${SRC_ROOT} " rm -rf freeswitch git clone --depth 1 --branch "${FS_VERSION} " https://github.com/signalwire/freeswitch.git } enable_module_line () { local module_line="$1 " local file="modules.conf" if grep -qx "${module_line} " "${file} " ; then return fi if grep -qx "#${module_line} " "${file} " ; then sed -i "s|^#${module_line} $|${module_line} |" "${file} " return fi echo "${module_line} " >> "${file} " } build_freeswitch () { log "配置并编译 FreeSWITCH" cd "${SRC_ROOT} /freeswitch" ./bootstrap.sh -j sed -i '/^applications\/mod_av$/d' modules.conf sed -i '1i#applications/mod_av' modules.conf enable_module_line "endpoints/mod_sofia" enable_module_line "applications/mod_spandsp" enable_module_line "formats/mod_shout" enable_module_line "databases/mod_mariadb" export PKG_CONFIG_PATH="${PKG_CONFIG_PATH_VALUE} " ./configure --prefix="${INSTALL_PATH} " --enable-core-pgsql-support make -j"${JOBS} " make install make cd-sounds-install make cd-moh-install } install_user_and_links () { log "配置用户、权限和命令链接" ln -sf "${INSTALL_PATH} /bin/fs_cli" /usr/bin/fs_cli ln -sf "${INSTALL_PATH} /bin/freeswitch" /usr/bin/freeswitch if ! getent group freeswitch >/dev/null; then groupadd freeswitch fi if ! getent passwd freeswitch >/dev/null; then useradd -r -g freeswitch -d "${INSTALL_PATH} " -s /sbin/nologin freeswitch fi chown -R freeswitch:freeswitch "${INSTALL_PATH} " chmod -R ug+rw "${INSTALL_PATH} " echo "${INSTALL_PATH} /lib" > /etc/ld.so.conf.d/freeswitch.conf ldconfig } build_mod_audio_fork () { log "编译安装 mod_audio_fork" cd "${DEPS_ROOT} /mod_audio_fork" chmod +x build.sh FREESWITCH_INCLUDE_DIR="${INSTALL_PATH} /include/freeswitch" \ FREESWITCH_LIBRARY="${INSTALL_PATH} /lib/libfreeswitch.so" \ FREESWITCH_MOD_DIR="${INSTALL_PATH} /lib/freeswitch/mod" \ BUILD_TYPE=Release \ ./build.sh build FREESWITCH_INCLUDE_DIR="${INSTALL_PATH} /include/freeswitch" \ FREESWITCH_LIBRARY="${INSTALL_PATH} /lib/libfreeswitch.so" \ FREESWITCH_MOD_DIR="${INSTALL_PATH} /lib/freeswitch/mod" \ BUILD_TYPE=Release \ ./build.sh install chown freeswitch:freeswitch "${INSTALL_PATH} /lib/freeswitch/mod/mod_audio_fork.so" chmod 755 "${INSTALL_PATH} /lib/freeswitch/mod/mod_audio_fork.so" } enable_runtime_modules () { local modules_xml="${INSTALL_PATH} /etc/freeswitch/autoload_configs/modules.conf.xml" if [ ! -f "${modules_xml} " ]; then log "未找到 ${modules_xml} ,跳过运行时模块配置" return fi for module in mod_shout mod_mariadb mod_audio_fork; do if grep -Eq "^[[:space:]]*<load module=\"${module} \"/>" "${modules_xml} " ; then continue fi if grep -Eq "^[[:space:]]*<!--[[:space:]]*<load module=\"${module} \"/>[[:space:]]*-->" "${modules_xml} " ; then sed -i "s|^[[:space:]]*<!--[[:space:]]*<load module=\"${module} \"/>[[:space:]]*-->.*| <load module=\"${module} \"/>|" "${modules_xml} " else sed -i "/<\/modules>/i\ <load module=\"${module} \"/>" "${modules_xml} " fi done chown freeswitch:freeswitch "${modules_xml} " } verify_install () { log "安装结果验证" test -x "${INSTALL_PATH} /bin/freeswitch" test -x "${INSTALL_PATH} /bin/fs_cli" test -f "${INSTALL_PATH} /lib/freeswitch/mod/mod_sofia.so" test -f "${INSTALL_PATH} /lib/freeswitch/mod/mod_spandsp.so" test -f "${INSTALL_PATH} /lib/freeswitch/mod/mod_shout.so" test -f "${INSTALL_PATH} /lib/freeswitch/mod/mod_mariadb.so" test -f "${INSTALL_PATH} /lib/freeswitch/mod/mod_audio_fork.so" "${INSTALL_PATH} /bin/freeswitch" -version if ldd "${INSTALL_PATH} /lib/freeswitch/mod/mod_audio_fork.so" | grep -i 'not found' ; then fail "mod_audio_fork has unresolved shared libraries" fi } main () { require_root ensure_almalinux9 install_packages clone_deps build_libks build_sofia build_spandsp build_signalwire_c clone_freeswitch build_freeswitch install_user_and_links build_mod_audio_fork enable_runtime_modules verify_install echo "===============================================================" echo "FreeSWITCH ${FS_VERSION} 与 mod_audio_fork 安装成功" echo "可用命令: freeswitch -ncwait, fs_cli" echo "===============================================================" } main "$@ "
执行:
1 2 chmod +x freeswitch_install.sh./freeswitch_install.sh
关键设计 1. 只允许 AlmaLinux 9 脚本开头做了系统校验:
1 2 3 4 . /etc/os-release if [ "${ID:-} " != "almalinux" ] || [[ "${VERSION_ID:-} " != 9* ]]; then fail "该脚本仅支持 AlmaLinux 9" fi
这个限制是有必要的。RHEL 系发行版之间包名、仓库、库目录都有差异。比如 AlmaLinux 9 需要启用 CRB,库目录也通常是 /usr/lib64。
2. 固定源码依赖版本 脚本固定了这几个版本:
1 2 3 4 5 libks v2.0.10 sofia-sip v1.13.17 spandsp fs 分支 signalwire-c v2.0.5 FreeSWITCH v1.10.12
FreeSWITCH 源码编译时,依赖版本漂移很容易造成 configure 失败、模块缺失或者运行时 动态库找不到。安装脚本要稳定,最好不要每次拉默认分支。
3. 明确 lib64 AlmaLinux 9 下,CMake 和 autotools 安装依赖时都显式指定 lib64:
1 2 -DCMAKE_INSTALL_LIBDIR=lib64 ./configure --prefix=/usr --libdir=/usr/lib64
同时设置:
1 PKG_CONFIG_PATH=/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig
否则 configure 阶段经常会出现库已经安装了,但是 pkg-config 找不到的情况。
4. 编译但禁用 mod_av 脚本里主动把 applications/mod_av 注释掉:
1 2 sed -i '/^applications\/mod_av$/d' modules.conf sed -i '1i#applications/mod_av' modules.conf
mod_av 依赖 ffmpeg 相关库,在部分 EL9 环境里容易拉出额外依赖问题。如果当前业务主要是 SIP、RTP、ASR/TTS 音频桥接,不一定需要它。
5. 一起安装 mod_audio_fork mod_audio_fork 是把 FreeSWITCH 通话音频通过 WebSocket 推给 ASR 服务的关键模块。 脚本把它作为安装流程的一部分:
1 2 3 4 5 FREESWITCH_INCLUDE_DIR="/usr/local/freeswitch/include/freeswitch" \ FREESWITCH_LIBRARY="/usr/local/freeswitch/lib/libfreeswitch.so" \ FREESWITCH_MOD_DIR="/usr/local/freeswitch/lib/freeswitch/mod" \ BUILD_TYPE=Release \ ./build.sh build
然后安装到 FreeSWITCH 的模块目录:
1 2 3 ./build.sh install chown freeswitch:freeswitch /usr/local/freeswitch/lib/freeswitch/mod/mod_audio_fork.sochmod 755 /usr/local/freeswitch/lib/freeswitch/mod/mod_audio_fork.so
脚本还会在 autoload_configs/modules.conf.xml 中确保以下模块加载:
1 2 3 <load module ="mod_shout" /> <load module ="mod_mariadb" /> <load module ="mod_audio_fork" />
启动前配置 配置目录:
1 /usr/local/freeswitch/etc/freeswitch
修改 vars.xml:
1 2 3 4 <X-PRE-PROCESS cmd ="set" data ="default_password=请改成强密码" /> <X-PRE-PROCESS cmd ="set" data ="bind_server_ip=$${domain}" /> <X-PRE-PROCESS cmd ="set" data ="external_rtp_ip=$${domain}" /> <X-PRE-PROCESS cmd ="set" data ="external_sip_ip=$${domain}" />
如果使用 PostgreSQL,可以在 autoload_configs/switch.conf.xml 里设置:
1 2 <param name ="core-db-dsn" value ="pgsql://hostaddr=数据库IP dbname=freeswitch user=用户名 password=密码 options='-c statement_timeout=3000' connect_timeout=5 keepalives=1 keepalives_idle=30 keepalives_interval=5 keepalives_count=3" />
在 sip_profiles/internal.xml 和 external.xml 中设置:
1 2 <param name ="odbc-dsn" value ="pgsql://hostaddr=数据库IP dbname=freeswitch user=用户名 password=密码 options='-c statement_timeout=3000' connect_timeout=5 keepalives=1 keepalives_idle=30 keepalives_interval=5 keepalives_count=3" />
验证 脚本最后已经做了一轮基础验证:
1 2 3 4 5 6 7 8 9 test -x /usr/local/freeswitch/bin/freeswitchtest -x /usr/local/freeswitch/bin/fs_clitest -f /usr/local/freeswitch/lib/freeswitch/mod/mod_sofia.sotest -f /usr/local/freeswitch/lib/freeswitch/mod/mod_spandsp.sotest -f /usr/local/freeswitch/lib/freeswitch/mod/mod_shout.sotest -f /usr/local/freeswitch/lib/freeswitch/mod/mod_mariadb.sotest -f /usr/local/freeswitch/lib/freeswitch/mod/mod_audio_fork.so/usr/local/freeswitch/bin/freeswitch -version ldd /usr/local/freeswitch/lib/freeswitch/mod/mod_audio_fork.so
安装后启动:
1 2 freeswitch -ncwait fs_cli
在 fs_cli 中检查:
1 2 3 4 5 version status sofia status module_exists mod_audio_fork module_exists mod_spandsp
线上注意事项
mod_audio_fork 依赖的共享库必须全部能被 ldd 找到,否则 FreeSWITCH 启动时会加载失败。
mod_audio_fork 只是媒体桥接模块,ASR WebSocket 服务的地址、子协议、鉴权仍需要在业务侧和 dialplan 中配置好。
ESL 8021、SIP 5060、RTP 端口不要无脑开放公网。SIP 可以按线路来源白名单开放,ESL 应只允许 内网业务服务器访问。
改 modules.conf 后要重新编译;改 modules.conf.xml 后通常 reloadxml 或重启模块即可。
修改 profile、ACL、NAT IP 后,建议执行:
1 2 3 fs_cli -x reloadxml fs_cli -x "sofia profile internal restart" fs_cli -x "sofia profile external restart"
重启 profile 会影响当前 SIP 注册和通话,线上要安排窗口。