FreeSWITCH 简单图形化界面54 - 拨号应用att_xfer协商转移使用
- [00、 一个fs的web配置界面预览](#00、 一个fs的web配置界面预览)
- [01、 Web 配置界面预览](#01、 Web 配置界面预览)
- [02、 Web界面安装参考](#02、 Web界面安装参考)
- [1.att_xfer 简介](#1.att_xfer 简介)
- [2. 用法](#2. 用法)
- [3. 可配置 DTMF 按键(通道变量)](#3. 可配置 DTMF 按键(通道变量))
- [4. 示例](#4. 示例)
-
- [示例 1:拨号计划实现 attended 转接](#示例 1:拨号计划实现 attended 转接)
- [示例 2:带自定义按键的完整配置](#示例 2:带自定义按键的完整配置)
- [示例 3:API/事件套接字调用](#示例 3:API/事件套接字调用)
- [示例 4:使用lua脚本进行协商转移](#示例 4:使用lua脚本进行协商转移)
- [5. 按键行为总结](#5. 按键行为总结)
- [6. 注意事项](#6. 注意事项)
00、 一个fs的web配置界面预览
如果您想通过图形化界面管理 FreeSWITCH 的场景,可直接访问以下 Web 配置界面。
01、 Web 配置界面预览
| 界面地址 | 备用地址 | 登录信息 |
|---|---|---|
| http://www.fspbx.cn/ | http://myfs.f3322.net:8020/ | 用户名:admin密码:admin |
02、 Web界面安装参考
若需自行部署 FreeSWITCH 图形化界面,包含 Docker、脚本、ISO 镜像三种安装方式,适配不同系统环境:
- 安装指南地址:https://blog.csdn.net/jia198810/article/details/137820796
- 核心安装方式概览:
- Docker 安装:快速部署;
- 脚本安装:适配 Almalinux、RockyLinux、Debian、Ubuntu 、欧拉等系统,提供一键安装命令,安装后需重启初始化;
- ISO 镜像安装:基于 Almalinux制作的镜像,刻录到 U 盘或光盘后可自动安装,适合全新服务器部署。
1.att_xfer 简介
att_xfer = Attended Transfer(专人值守转接/协商转接)
用于执行"有人值守转接"(Attended Transfer)。该功能允许通话的一方在转接前先与第三方通话,确认无误后,再将原始通话的另一方与用户C桥接。
典型使用场景
A打电话找 C,B是前台/秘书,B 接到 A的来电后,进行协商转移:
A 来电 → 被 B 接听
B 启动 att_xfer 功能,呼叫 C
A被保持(Hold),B与 C 进行私密通话
C 同意接听 A 的电话 → B 挂机 → A 与 C 建立通话
C 拒绝接听 A 的电话 → C 挂机 → A 返回与 B 的通话
B 在私密通话中按功能键可执行不同操作
2. 用法
xml
att_xfer <channel_url>
3. 可配置 DTMF 按键(通道变量)
| 通道变量 | 默认按键 | 功能说明 |
|---|---|---|
| attxfer_cancel_key | # | 取消转接,挂断 C 端,回到原通话 A |
| attxfer_hangup_key | * | 挂断坐席,直接桥接 A ↔ C(完成转接) |
| attxfer_conf_key | 0 | 转为三方通话,再挂断坐席完成转接 |
4. 示例
示例 1:拨号计划实现 attended 转接
- 定义转接扩展:
xml
<extension name="att_xfer">
<condition field="destination_number" expression="^86$">
<action application="read" data="3 4 sounds/getdigits.wav attxfer_callthis 30000 #"/>
<action application="att_xfer" data="sofia/default/${attxfer_callthis}"/>
</condition>
</extension>
- 绑定到 DTMF 快捷键(通话中按
*3触发):
xml
<action application="bind_meta_app" data="3 a a execute_extension::86 XML features"/>
示例 2:带自定义按键的完整配置
主叫拨号计划:
xml
<extension name="local_number">
<condition field="destination_number" expression="^(\d{3})$">
<action application="set" data="dialed_extension=$1"/>
<action application="export" data="dialed_extension=$1"/>
<action application="bind_meta_app" data="1 b s execute_extension::attended_xfer XML features"/>
<action application="set" data="transfer_ringback=$${hold_music}"/>
<action application="set" data="call_timeout=10"/>
<action application="set" data="hangup_after_bridge=true"/>
<action application="bridge" data="user/${dialed_extension}@${domain_name}"/>
</condition>
</extension>
features.xml 中的转接逻辑:
xml
<extension name="attended_xfer">
<condition field="destination_number" expression="^attended_xfer$">
<action application="set" data="continue_on_fail=true"/>
<action application="read" data="3 4 ivr/ivr-enter_ext.wav attxfer_callthis 30000 #"/>
<action application="set" data="attxfer_cancel_key=#"/>
<action application="set" data="attxfer_hangup_key=*"/>
<action application="set" data="attxfer_conf_key=0"/>
<action application="att_xfer" data="user/${attxfer_callthis}@${domain_name}"/>
</condition>
</extension>
示例 3:API/事件套接字调用
att_xfer {attxfer_conf_key=3,attxfer_hangup_key=2,attxfer_cancel_key=1}user/1000
示例 4:使用lua脚本进行协商转移
lua
#!/usr/bin/env lua
-- 2024年7月2日
-- 功能号码
-- 呼叫协商转移
------------------打印日志-------------------
-- CONSOLE : console loglevel 0
-- ALERT : console loglevel 1
-- CRIT : console loglevel 2
-- ERR : console loglevel 3
-- WARNING : console loglevel 4
-- NOTICE : console loglevel 5
-- INFO : console loglevel 6
-- DEBUG : console loglevel 7
local flag = true
local level = "NOTICE"
local log = function(session, str)
if (flag == true and session:ready()) then
session:consoleLog(level, str)
end
end
if (session:ready()) then
local caller_id_name = session:getVariable("caller_id_name")
local caller_id_number = session:getVariable("caller_id_number")
local destination_number = session:getVariable("destination_number")
local domain = session:getVariable("domain")
local context = session:getVariable("context")
log(session, "#======= start handle-att-xfer.lua =======\r\n")
log(session, string.format("# 主叫:%s,被叫:%s,开始协商转移.\r\n", caller_id_number, destination_number))
-- 播放等待音
session:execute("set", "transfer_ringback=$${hold_music}")
-- 自定义取消转移、挂机、3方通话按键
session:execute("set", "attxfer_cancel_key=1")
session:execute("set", "attxfer_hangup_key=2")
session:execute("set", "attxfer_conf_key=3")
-- 获取用户输入(要转移到的号码,C号码)
local digits = session:playAndGetDigits(1, 12, 3, 5000, "#", "default/att-xfer-start.gsm",
"default/att-xfer-error.gsm", "\\d+")
if (digits == '') then
session:execute("playback", "default/blind-xfer-end.gsm")
else
-- 获取转发的分机的相关信息(限制转移的号码,只有被叫号码(C)是内部号码才能盲转,只能转到内部号码)
fsapi = freeswitch.API();
local is_local_number = fsapi:executeString(string.format("user_exists id %s %s", digits, domain));
if (is_local_number == "true") then
log(session, string.format("# 要转移的号码%s是内部号码,正在转移.\r\n", digits))
session:execute("set", string.format("caller_id_name=%s",caller_id_name))
session:execute("set", string.format("caller_id_number=%s",caller_id_number))
session:execute("set", string.format("destination_number=%s",destination_number))
-- session:execute("set", string.format("rdnis=%s",destination_number))
session:execute("export", string.format("nolocal:caller_id_name=%s",caller_id_name))
session:execute("export", string.format("nolocal:caller_id_number=%s",caller_id_number))
session:execute("export", string.format("nolocal:destination_number=%s",digits))
session:execute("set", "process_cdr=true")
-- 这里执行att_xfer协商转移应用
session:execute("att_xfer", string.format("user/%s@%s", digits, domain))
else
log(session, string.format("# 要转移的号码%s不是内部号码,无法转移.\r\n", digits))
session:sleep(500)
session:execute("playback", "default/user-cannot-connected-start.gsm")
for i = 1, string.len(digits) do
local digit = string.sub(digits, i, i)
session:execute("playback", string.format("default/digits/%s.wav", digit))
end
session:execute("playback", "default/user-cannot-connected-end.gsm")
session:execute("playback", "default/blind-xfer-end.gsm")
end
end
log(session, "#======= end handle-att-xfer.lua =======\r\n")
-- return
end
5. 按键行为总结
- 接通 C 端后按 0 → 进入三方会议
- 接通 C 端后按 # → 取消转接,回到 A
- 接通 C 端后按 * → 坐席退出,A 与 C 直接通话
- C 端未接通时按 # → 取消 C 端呼叫,回到 A
6. 注意事项
- att_xfer 不支持 loopback 通道:桥接到 C 端时会阻塞;
- 如果 C 端挂断,会自动回到 A 端;
- loopback 本身会通过挂断来切换通道,会被 att_xfer 识别并切回 A。
💗 2026年
🐂 祝君成功,好运连连,牛气冲天