在漫长的通信历史长河中,PSTN以及电话交换技术的发展经历了很多阶段,如从直接控
制到间接控制再到公共控制、从人工交换到自动交换、从点子交换到程控交换、从模拟到
数字、从电路交换到分组交换、从“硬”交换到软交换。
第一次语音传输是苏格兰人亚历山大·贝尔(Alexander Granham Bell)在1876年用振铃电
路实现的。
振铃电路实现是没有电话号码的,通话用户之间必须由物理线路连接,同一时间只能一个
用户讲话。
交换机(Switch,又称Exchange)的设备诞生了,线路大大减小。交换连续工作全部由人工
完成。
1889年到1891年期间,美国阿尔蒙·B·史端桥(Almon B Strowger)发明了步进式自动电话交
换机。属于“直接控制”方式。
以后,又出现了旋转式和升降式的交换机。采用“记发器”的部件来接收用户的拨号脉冲,属于
“间接控制”方式。
1919年,瑞典的电话工程师帕尔姆格伦和贝塔兰德发明了“纵横制连接器”。把控制器和话路器
分开。控制部分由标志器和记发器来完成。
控制部分引入了电子技术,而话路部分在较长的一段时间内仍采用机械触电。
1965年5月,美国布尔系统的1号电子交换机(ESS No.1)问世了,这是世界上第一部开通使用
的程控电话交换机。当时的交换机话路部分还保留了机械触电,以“空分”方式工作,因此称为
空分交换机。交换的还是模拟信号。
20世纪60年代初以来,脉冲编码调制(PCM)技术成功地应用于传输系统中,它将“模拟”的信号
数字化,提高了通话质量、增加了传输距离,节约了许多线路成本。1970年,法国开通了世界上
第一部程控数字交换机E10,开始了数字交换的心时代。
随着技术的进步和通信要求的增加,世界上许许多多的交换机也需要相互通信,这些交换机之间
通过中继线(Trunk)相连,随着电子交换机和程控交换机的发展,便出现了现代意义的PSTN网
络。
20世纪70年代后期出现了蜂窝式移动电话(当移动电话小到可以拿到手里的时候就开始叫“手机”了
)系统,这是无线电话发展的里程碑。无限电话的出现,扩展了PSTN网络能力和范围,对PSTN网络
的影响及其深远。
专门用于移动电话交换的通信网络称为移动网,而原来的程控交换网则称为固定电话网,简称固网。
简单来说,移动网就是在普通固网上增加了许多基站(Base Station,可以简单理解为天线),并
增加了归属位置寄存器(Home Location Register,HLR)和拜访位置寄存器(Visitor Location
Register,VLR),以记录用户的位置()、支持异地漫游等。移动交换中心称为MSC(Mobile Switch
Center)。
随着分组交换的成熟及英特网的发展,人们认识到了将原始的基于电路交换的语音网络与基于分组
交换的英特网络进行融合(即语音通信和数据通信相结合)的必要性,因此一个称为NGN(Next
Generation Network)的概念被提了出来。
经过数年的研究和探索,人们提出了各种NGN解决方案,但最终基本上都统一到了IMS(IP Multimedia
Subsystem)技术。
IMS属于核心交换层的技术,它全部基于IP网络,但在接入层,目前的语音大部分还是基于电路接入
的方式接入的,因此,在一定时间内IMS在接入层要继续兼容电路接入。未来的通信中要求完全取消
低效的电路传输及电路交换,而全部集中在IP通信上来,也就催生了新的无限通信标准LTE。
关于通信网络的演进,简单来说,在无线方面体现为从GSM/CDMA/UMTS等向LTE发展,在核心网方面则
体现为电路交换向IMS发展。
现行的电话网中采用E.164号码格式。
移动电话号码俗称手机号,由于其可移动与漫游的特性,与普通固定电话略有不同。我国的移动电话
都是以1开头,按不同的运营商来划分。
有一类特殊的号码称为短号码,如110,119,120等。
800号码用手机打不通,400是可以手机呼叫的。
加拿大和美国使用北美电话号码分类计划,其区号由3位数字组成,本地号码为7位数字,1为长途接入
码,即长途字冠。
国内号码的书写一般采用如下的方式:
模拟(Analog)量是连续的变化的量。容易引入噪音。
数字(Digital)信号是不连续的(离散的)。
PCM(Pulse Code Modulation)的全称是脉冲编码调制。它是一种通用的将模拟信号转换成以0和1表示
的数字信号的方法。
人的音频范围在300~3400Hz之间,通过滤波器将超过4000Hz的频率过滤出去,便得到4000Hz内的模拟信
号。然后根据抽样定理,使用8000Hz进行抽样,便得到离散的数字信号。使用PCM方法得到的数字信号
就称为PCM信号,一般一次抽样会得到16bit的信息。
使用压缩算法,可以将每一个抽样值压缩到8bit。这样1秒的抽样就得到8bit×8000=640000bit信号(简称
64kbit),抽样速率(即传输速率)为64Kbit/s。
PCM通常有两种压缩方式:A律和μ率。北美使用μ律,我国和欧洲使用A率。
连接交换机(局)的E1或T1电路称为局间中继。
我国电话网由本地网与长途网组成,并通过国际交换中心进入国际电话网。
用户设备(如话机)与端局交换机之间,以及交换机与交换机之间需要进行通信。这些通信所包含的信息有
(但不限于)用户、中继线状态、主叫号码、被叫号码、中继路由的选择等。我们把这些消息称为
信令(Signaling)。
按信令的功能分
按信令的工作区域分
按信令的信道分
其他分类
信令还可以分为带内信令和带外信令、模拟信令和数字信令、向前信令和向后信令、线路信令和记发器信令等。
从用户终端(通常是话机)到端局交换机之间经常需要传送一些控制信息,如用户摘机、挂机、拨号、主叫号码
显示等,这些信息称为用户线信令。用户线信令可以通过模拟或数字信号传递。
交换机与交换机之间也需要传送控制信号,用于话路的建立、释放等,这些信号就称为局间信令。
目前在传统的PSTN网络中常见的局间信号有ISDN PRI(Primary Rate Interface,基群速率接口)信令和七号信令。
PRI信令和话路在同一个E1上传送。七号信令可以与话路在同一个E1上传送外,还可以在专门的用于传送信令链路的
E1中继上传送。
七号信令(Signaling System No.7,SS7)是我国目前使用的主要信令方式,用于局间通信。我国的电话网络中有专
门的七号信令网。
由于ISUP(ISDN User Part,ISDN用户部分)能与ISDN互联并提供比TUP更多的能力和服务,故其已基本取代TUP成为
我国七号信令网采用的主要信令方式。
H.323与SIP属于VoIP领域的通信信令,它们适用于用户线信令和局间信令。
H.323是ITU多媒体通信系列标准H.32x的一部分,该系列标准使得在现有通信网络上进行视频会议称为可能。
SIP(Session Initiation Protocol,会话发起协议)是由IETF(Interne 工程任务组)提出的IP电话信令
协议。
信令主要传输一些控制信号,而通信双方需要听到的是对方的语音数据,这些语音数据就称为媒体(Media).
在SIP通信中,除文字外,媒体都是在RTP协议中传输的。由于媒体一般都是持续传输的,因此又称RTP流。
传统电路交换,两个通信节点间需要建立一个专用通路。而报文交换以报文作为数据交换单位,携带目标地址、源地址
等信息。分组交换是报文交换的特殊情形。
传统的电话都是基于电路交换的。
电路交换的优点:
电路交换的缺点:
IP交换采用的就是分组交换方式。
分组交换的优点:
分组交换的缺点:
IP电话(Voice over Internet Protocol,VoIP,又称宽带电话或网络电话)是一种透过互联网或其他使用
IP技术的网络来实现的新型电话通信。
目前,VoIP呼叫控制协议主要有SIP、H.323、MGCP与H.248/MEGACO等。
IMS的全称是IP多媒体子系统(IP Multimedia Subsystem),它是一个基于IP网提供语音及多媒体的网络体系
架构。
(1)CSCF
CSCF(Call Sessoin Control Function,呼叫会话控制功能)。
(2)MGCF
MGCF(Media Gateway Control Function,媒体网关控制功能)
(3)IM-MGW
IM-MGW(IP Multimedia-Media Gateway Function,多媒体网关功能)
(4)MRF
MRF(Multimedia Resource Function,多媒体资源功能)分成两部分,包括MRFC(Multimedia Resource Function
Controller,多媒体资源功能控制器)和MRFP(Multimedia Resource Function Processor,多媒体资源功能处理器)。
(5)SLF
SLF(Subscription Locator Function,签约定位功能)
(6)HSS
HSS(Home Subscriber Server,归属用户服务功能)
(7)BGCF
BGCF(Breakout Gateway Control Function,出口网关控制功能)
(8)SGW
SGW(Singnalling Gateway Function,信令网关功能)
(9)AS
AS(Application Server,应用服务器)
PSTN除了为用户提供基本的语音通话外,还能提供一些附加的业务,如叫醒业务、呼叫转移等。
POTS(Plain Old Telephone Service)及普通老式电话业务。
(1)模拟中继线
(2)数字中继线
(3)虚拟网
(4)立即计费
(5)VPN
包括预付费业务(电话卡类业务等)、800业务、400业务以及彩铃、电话秘书台等。
PBX(Private Branch eXchange)的全称是专用小交换机。
用户或企业PBX要想打通外面的电话,或者外面的电话需要打进来,需要走运营商提供的中继线,
以接入到PSTN网上。
FreeSWITCH的默认配置就是一个家用或小型企业级PBX,它是由纯软件实现的,基于IP网进行通信,
因而又称为IP-PBX。
IP-PBX首先是一个PBX(Private Branch eXchange),它具有传统PBX的绝大部分功能。另外,由于
使用了IP通信,它能够通过IP网提供语音、视频以及即时消息通信。
基于企业级的PBX和IP-PBX的通信还只是局限于基础的通信层。而随着企业规模的扩大以及用户对服务
要求的提高,企业需要在业务层和管理层方面为用户提供更好的服务。当这些服务可以通过远程电话
支持的方式解决的情况下,一种称为呼叫中心的业务(Call Center)便产生了。
呼叫中心又称客户服务中心,它是一种基于CTI技术、充分利用通信网和计算机网的多项功能集成,并
与企业连为一体的一个完整的综合信息服务系统,利用现有的各种先进的通信手段,高效的为客户提供
高质量、高效率、全方位的服务。
通俗的将,呼叫中心是企业或机构建立的以电话为主的主要手段,为客户提供服务于沟通的部门组织及
信息系统。
(1)第一代呼叫中心
PBX基础上增加电话排队。
(2)第二代呼叫中心
IVR(Interactive Voice Response,交互式语音应答)系统的使用。
(3)第三代呼叫中心
CTI(Computor Telephony Integration,计算机电话集成)技术的应用。
(4)第四代呼叫中心
多媒体呼叫中心或联络中心(Contact Center)。
(5)下一代呼叫中心
融入互联网技术的媒体渠道与沟通渠道。
按照呼叫中心系统采用的技术架构的不同,呼叫中心可以分为交换机、板卡、软交换(IPCC)三种类型。
常见的KPI指标有接通率、呼入项目占有率、呼出项目工作效率、服务水品、客户满意度、平均振铃次数、
监听合格率、一次性解决问题率等。
CTI(Computer Telephony Integration,计算机电话集成)。
交换机设备厂商开始考虑为交换机增加一个可以受计算机系统控制的接口,有计算机系统通过某种协议
获取交换机用户话机的状态信息以及对呼叫的控制命令。这种连接和控制接口称为CTI-Link。
CTI中间件在下层通过对各种CTI-Link协议的包装和抽象,屏蔽了各种交换机的不同,在上层为呼叫中心
业务软件开发人员提供统一的API开发接口。
(1)语音交换功能
(2)媒体处理功能
(3)媒体监播功能
(4)电话会议功能
(5)电子传真功能
(6)排队功能
FreeSWITCH是一个开源的电话交换平台。官方给它的定义是–世界上第一个跨平台的、伸缩性极好的、免费
的、多协议的电话软交换平台。
典型功能:
FreeSWITCH支持Linux、Windows、Mac平台。
FreeSWITCH的版本号很有规律:版本号有3部分,以点号隔开。其中第1位为主版本,第2位为次版本,第3位作补丁及
更新标志。其中,从第2位看,偶数的版本为稳定版,奇数版本为开发版。
(1)使用安装包安装
下载地址:http://files.freeswitch.org/windows/installer/
(2)从源码安装
下载地址:http://files.freeswitch.org/freeswitch-releases/
Microsoft提供Visual Studio工具进行开发。
相关环境
CentOS:
yum install -y autoconf automake libtool gcc-c++ ncurses-devel make zlib-devel libjpeg-devl
yum install -y openssl-devel e2fsprogs-devel curl-devel pcre-devel speex-devel sqlite-devel
Ubuntu/Debian:
apt-get -y install build-essential automake autoconf git-core wget libtool
apt-get -y install libncurese5-dev libtiff-dev libjpeg-dev zliblg-dev libssl-dev libsqlite3-dev
apt-get -y install libpcre3-dev libspeexdsp-dev libspeex-dev libcurl4-openssl-dev libopus-dev
(1)从Git仓库安装
git clone git://git.freeswitch.org/freeswitch.git
cd freeswitch #进入源代码目录
git checkout -b v1.2.12 #根据一个tag检出到一个本地分支
或
git checkout -b v1.4.beta #从远程分支检出一个本地分支
或
git clone -b v1.4.beta git://git.freeswitch.org/freeswitch.git #直接在复制时指定一个分支
(2)解压缩源码包安装
wget http://files.freeswitch.org/freeswitch-1.4.0.beta6.tar.bz2
tar xvjf freeswitch-1.4.0.beta6.tar.bz2
cd freeswitch-1.4.0
./configure
make install
(3)最快安装
wget http://www.freeswitch.org.cn/Makefile && make install
需要先下载Apple的Xcode工具,安装命令行工具(Command Line Tools)
FreeSWITCH也依赖于一些第三方的库。一般使用Macports、Flink和HomeBrew等工具包。
ruby -e "$(culr -fsSl https://raw.github.com/mxcl/homebrew/go)"
安装Git和libtiff库
brew install git
brew install libtiff
其他全部和Linux一样
git clone git://git.freeswitch.git/freewitch.git
cd freeswitch
./bootstrap.sh
./configure
make install
声音文件有2种,一种是提示音,另一种是音乐。
在windows是默认安装的。而在Linux和Mac上安装这些声音,源码目录中执行:
make sounds-install
make moh-install
FreeSWITCH使用make install 安装完成后,会显示一个有用的帮助。
建议将两个命令做符号链接放到你的搜索路径中,如:
ln -sf /usr/local/freeswitch/bin/freeswitch /usr/bin/
ln -sf /usr/local/freeswitch/bin/fs_cli /usr/bin/
启动在前台,输入shutdown
关闭
freeswitch -nc
后台模式, freeswitch -stop
关闭FreeSWITCH
不管前台还是后台,都可以使用客户端软件fs_cli
连接到它并控制
/exit
或按Ctrl+D
组合键,退出终端。
FreeSWITCH最典型的应用是作为一个服务器,并用电话客户端软件连接到它。
FreeSWITCH主要使用的通信协议是SIP。
支持SIP的软电话常用的有X-Lite和Zoiper。
X-Lite配置:
选“Sip Account Setting…”,单击“Add”添加一个账号,填入一下参数:
Display Name:1000
User Name:1000
Password:1234
Authorization user name:1000
Domain:FreeSWITCH服务所在的IP地址
FreeSWITCH配置文件默认放在conf/下。
conf/目录和文件 | 说明 |
---|---|
–vars.xml | 一些常用变量 |
–switch.xml | 主配置文件,它会使用include语句装入其他文件 |
–autoload_configs | 目录,存放自动加载的配置文件 |
—-modules.conf.xml | 配置当FreeSWITCH启动时自动装载哪些模块 |
—-*.xml | 一般来说每个模块都有一个配置文件 |
–chatplan | 聊天计划 |
–dialplan | 拨号计划 |
—-default.xml | 默认的拨号计划配置,一般用于内部用户路由 |
—-public.xml | 默认的拨号计划配置,一般用于外部来的路由 |
–drectory | 用户目录 |
—-default | 默认的用户目录配置 |
——*.xml | SIP用户,每用户一个文件 |
–ivr_menus | IVR菜单 |
–jingle_profiles | 连接Google Talk的相关配置 |
–lang | 多语言支持 |
—-en | 英语 |
—-fr | 法语 |
–mrcp_profiles | MRCP的相关配置,用于跟第三方语音合成和语音识别系统对接 |
–sip_profiles | SIP配置文件 |
—-internal.xml | 一个SIP profile,或称作一个SIP-UA,监听在本地IP及端口5060 |
一般供内网用户使用 | |
—-externa.xml | 另一个SIP-UA,用作外部连接,端口5080 |
–skinny_profiles | 思科SCCP协议话机的配置文件 |
FreeSWITCH默认设置了20个用户,如果你需要更多的用户,3步:
conf/directory/default/
中增加一个配置文件。也可以把FreeSWITCH简单地用作一个软电话。目前唯一支持CELT高清通话的软电话。
FreeSWITCH使用mod_portaudio模块支持你本地的音频设备,默认是不编译的。在源码目录执行:
make mod_portaudio
make mod_portaudio-install
安装完成后控制台执行:
load mod_portaudio
尝试以下命令:
pa looptest (回路测试,echo)
pa call 9196 (呼叫9196)
pa call 1000 (呼叫1000)
pa hangup (挂机)
如果你拥有某个运营商提供的SIP账号,那么你就可以通过配置SIP来拨打外部电话了。
该SIP账号(或提供该账号的设备)在FreeSWITCH中称为SIP网关(Gateway)。
添加网关需要在conf/sip_profiles/external/
中创建一个XML文件。如gwl.xml:
<gateway name="gwl">
<param name="realm" value="SIP服务器地址,可以是IP或IP:端口号"/>
<param name="username" value="SIP用户名"/>
<param name="password" value="密码"/>
gateway>
执行命令使之生效:
sofia profile external rescan
显示网关注册状态:
sofia status
如果显示gateway gwl
的状态是REGED
,则表明已正确地注册到了网关上。
先用命令试一下网关是否正常:
originate sofia/gateway/gwl/xxxxxx &echo
该命令会通过网关gwl呼叫号码xxxxxx,被叫号码接听电话后,FreeSWITCH会执行echo程序,
就能听到自己的回音了。
常见的PBX一般是内部拨小号,打外部电话就需要加拨0或先按9。
<include>
<extension name="call out">
<condition field="destination_number" expression="^0(\d+)$">
<action application="bridge" data="sofia/gateway/gwl/$1" />
condition>
extension>
include>
其中,匹配0后面的变量并存入到变量$1中。然后通过bridge程序通过网关gwl打出该号码。
一般来说,呼入的DID就是你的SIP号码。
创建XML文件放到conf/dialplan/public/my_did.xml
中:
<include>
<extension name="public_did">
<condition field="destination_number" expression="^(你的DID)$">
<action application="transfer" data="1000 XML default"/>
condition>
extension>
include>
一般来讲,FreeSWITCH不需要任何命令行参数就可以启动。
使用freeswitch -h
或freeswitch -help
或freeswitch --help
显示帮助信息
常用的两个:
freeswitch -nc #后台启动
freeswitch -nonat #关掉NAT启动
在调试阶段,可以将FreeSWITCH启动到前台,也可以启动到后台,通过查看log/freeswitch.log
跟踪系统运行情况。
在真正生成系统上,一般需要FreeSWITCH能跟系统一起启动。
- 在UNIX类系统上,启动脚本一般放在etc/init.d/
下。可以在源码目录下找到不同系统启动脚本debian/freeswitch.init
及build/freeswitch.init.*
。
- 在Windows上,可以将FreeSWITCH注册为服务。
UNIX类系统下:
(1)看进程是否存在。
ps aux | grep freeswitch
(2)看相关端口是否被占用。
netstat -an | grep 5060
netstat -anp | grep 5060
Windows平台:
netstat命令、任务管理器。
系统不带参数启动到控制台,在控制台上可以输入各种命令以控制或查询FreeSWITCH的状态。
version -- 显示当前版本
status -- 显示当前状态
sofia status -- 显示sofia状态
help -- 显示帮助
为了调试方便,还在conf/autoload_configs/switch.conf.xml
中定义了一些控制台快捷键。
FreeSWITCH是一个典型的Client/Server结构,不管FreeSWITCH运行在前台还是后台,你都可以使
用客户端软件fs_cli连接FreeSWITCH。
fs_cli使用FreeSWITCH的ESL协议与FreeSWITCH通信。
fs_cli也支持很多命令行参数,值得一提的是-x参数,它允许执行一条命令后退出。
$ bin/fs_cli -x "version" # 显示版本号
$ bin/fs_cli -x "status" # 显示状态
$ bin/fs_cli -x "originate user/1000 &bridge(user/1001)" # 回拨
fs_cli可以连接到其他机器上的FreeSWITCH,用户主目录编辑配置文件.fs_cli_conf
[server1]
host => 192.168.1.10
port => 8021
password => secret_password
debug => 7
[server2]
host => 192.168.1.11
port => 8021
password => secret_password
debug => 0
配置好,可以这样使用:
$ fs_cli server1
$ fs_cli server2
fs_cli有几个特殊命令,以”/”开头。这些命令不直接发送到FreeSWITCH,而是先由fs_cli处理。
使用originate
命令发起一次呼叫。
freeswitch> originate user/1000 &echo
呼叫1000,1000接听后,将听到回声。
“user/1000”称为呼叫字符串。
假设alice的UA地址为192.168.4.4:5090,已向FreeSWITCH注册。
freeswitch> sofia status profile internal reg
可以看到alice的注册信息。
使用originate命令呼叫user/alice这个呼叫字符串时,会找到Cantact地址sip:[email protected]:5090
并向其发送INVITE请求。
FreeSWITCH的命令不仅可以在控制台上使用,也可以在各种嵌入式脚本、Event Socket或HTTP RPC上使用,
所有命令都遵循一个抽象的接口,因而这些命令又称为API Commands。
echo则是一个常用的应用程序(Application,App),它的作用是控制一个Channel的一端。
alice是一端,另一端是echo。这种通话称为“单腿通话(one-legged connection)”。
可以将电话“挂起”,park便是实现这个功能。
hold比较友好,等待同时播放音乐。
freeswitch> originate user/alice &hold
播放特定的声音
freeswitch> originate user/alice &playback(/root/welcome.wav)
或直接录音
freeswitch> originate user/alice &record(/tmp/voice_of_alice.wav)
大多数情况下,FreeSWITCH都是作为一个B2BUA来桥接两个UA进行通话的。在alice接听电话后,bridge程序可以在启动一个UA呼叫bob
freeswitch> originate user/alice &brige(user/bob)
另一种方式
originate user/alice &park
originate user/bob &park
show channels
uuid_bridge <alice_uuid><bob_uuid>
分别呼叫alice和bob,然后通过uuid_bridge命令将两个Channel桥接起来
两条命令(API):originate和uuid_bridge
几个程序(App):echo、park和bridge
**简单来说,一个App是一个程序(Application),它作为一个Channel一端与另一端的UA进行通信,相当于它工作在Channel内部;
而一个API则是独立于一个Channel之外的,它只能通过找到Channel的UUID来控制一个Channel(如果需要的话),相当于一个第三者。**
这就是API和App最本质的区别。
使用help可以列出所有命令的帮助信息。
freeswitch> help
总的来说,FreeSWITCH由一个稳定的核心(Core)以及一些外围模块组成。
FreeSWITCH内部使用线程模型来处理并发请求,每个连接都在单独的线程中进行处理,不同的线程间通过Mutex互斥访问共享资源,并
通过消息和异步事件等方式进行通信。
FreeSWITCH的核心非常短小精悍。绝大多数应用层的功能都在外围模块中实现。外围模块通过核心提供的Public API与核心进行通信,
而核心则通过回调(或称钩子)机制执行外围模块中的代码。
FreeSWITCH的核心是Core,它包含了关键的数据结构和复杂的代码、状态机、数据库等,这些代码只出现在核心中,并保持了最大限度
的抽象和重用。外围模块只能通过核心代码提供的公共应用程序接口调用核心的功能。
FreeSWITCH的核心除了使用内部队列、哈希表存储数据外,也使用外部的关系型数据库存储数据。
核心层实现了一些Public API。这些Public API可以被外围的模块调用。
提供了很多抽象的接口,具体实现一般由外围的模块负责,核心层通过回调(钩子)方式调用具体的实现代码或函数。
内部也使用消息和事件机制进行进程间和模块间通信。
接口都是抽象的,其中只有少量在核心中有具体实现(如PCM编码解码实现),大部分最终由外部实现。
目录 | 说明 |
---|---|
bin | 可执行程序 |
db | 系统数据库(sqlite),将呼叫信息存放到数据库中,这样在查询时就无须对核心数据结构进行加锁了 |
htdocs | HTTP Server根目录 |
lib | 库文件 |
mod | 可加载模块 |
run | 运行目录,存放FreeSWITCH运行时PID |
sounds | 声音文件,使用playback()时默认的寻找路径 |
grammer | 语法,用于ASR |
include | 头文件 |
recordings | 录音,使用record()时默认的存放路径 |
scripts | 嵌入式语言写的脚本,如使用lua()、luarun()、jsrun等默认寻找的路劲 |
storage | 语音留言(Voicemail)的录音 |
conf | 配置文件 |
在系统装载时,XML解析器会将所有的XML文件组织在一起,并读入内存,组成一个大的XML文档(Document),称为XML注册表。
freeswitch.xml是所有XML文件的黏合剂。
vars.xml主要通过X-PRE-PROCESS指令定义了一些全局变量。如
<X-PRE-PROCESS cmd="set" data="domain=$${local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="domain_name=$${domain}"/>
<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>
<X-PRE-PROCESS cmd="set" data="use_profile=internal"/>
实际使用中,可以使用global_getvar或API命令来查看这些变量的值。
freeswitch> global_getvar sound_prefix
freeswitch> global_getvar local_ip_v4
autoload_config目录下的各种配置文件会在系统启动时装入。一般来说都是块级的配置文件,每个模块对应一个。
SIP并不要求一定要注册才能可以打电话,但是通话前的用户认证参数仍需要在用户目录中进行配置。
Bob到FreeSWITCH的通话称为来话,FreeSWITCH作为一个B2BUA再去呼叫Alice时,称为去话。
无论来话还是却话,都会启动一个Session,控制着整个呼叫,直到结束。每个Session都控制着一个Channel。
在逻辑上组成一个通话,称为Call。
A-交换机a-交换机b-B
为了在A端能听到B端特殊的回铃音,回铃音只能由B端交换机发送。这些回铃音称为Early Media。
理论上将,B接听电话后交换机b可以一直不向交换机a发送应答消息,而是将真正的话音数据伪装成Early Media,实现“免费通话”。
拨号计划主要作用就是对电话进行路由,决定和影响通话的流程。
可以是静态配置的,也可以使用动态配置方式从其他服务器或脚本中动态获取。
拨号计划由多个Context组成。每个Context中有多个Extension。Context就是多个Extension的逻辑集合,
它相当于一个分组。一个Context中的Extension与其他Context中的Extension在逻辑上是隔离的。
系统默认提供的配置文件包含三个Context,分别是default、feature和public。
使用与Perl兼容的正则表达式匹配算法。
每一次呼叫都由一条或多条“腿”(Call Leg)组成,其中的一条腿又称为一个Channel,每一个Channel都有很多属性,
用于标识Channel的状态、性能等,这些属性称为Channel Variable(通道变量)。
最简单的测试条件
<condition field="destination_number" expression="^1234$">
<condition field="network_addr" expression="^192\.168\.7\.7$">
Dialplan中的测试条件
变量 | 说明 |
---|---|
context | Dialplan当前的Context |
rdnis | 被转移的号码 |
destination_number | 被叫号码 |
diaplan | Dialplan模块的名字,如XML、YAML、inline、asterisk、enum等 |
caller_id_name | 主叫(来电显示)的名称 |
caller_id_number | 主叫号码 |
ani | 主叫的自动识别 |
aniii | 主叫类型,如投币电话 |
uuid | 本Channel的唯一标志 |
source | 呼叫源,来自哪一个FreeSWITCH模块 |
chan_name | Channel名字 |
network_addr | 主叫ip地址 |
year | 当前的年,0~9999 |
yday | 一年中的第几天,1~366 |
mon | 月,1~12 |
mday | 日,1~31 |
week | 一年中的第几周,1~53 |
mweek | 本月中的第几周,1~6 |
wday | 一周中的第几天,1~7 |
hour | 小时,0~23 |
minute | 分,0~59 |
minute-of-day | 一天中的第几分钟,(1~1440) |
接受用户在用户目录中设置的变量,但要注意必须使用${}对变量进行引用。
<condition field="${toll_allow}" expression="international">
测试条件不可嵌套,但可迭加。构成“逻辑与”关系。
break参数可以使condition构成其他关系。
除使用condition的break机制来完成复杂的条件以外,你还可以使用“反动作”来达到类似的目的。
new->init->routing<->execute->hangup->reporting->destory
ROUNTING和EXECUTE是属于两个不同的阶段,只有ROUTING完毕后才会进行EXECUTE阶段的操作。
在Hunting阶段,如果发现带有inline的Action,会直接执行它,而不用等到EXECUT阶段。
<action inline="true" application="set" data="greeting=no-greeting.wav" />
inline会打乱执行顺序,所以使用不当可能会产生非预期的结果。
<extension name="Local_Extension">
<condition field="destination_number" expression="^(10[01][0-9])$">
condition>
extension>
1000呼叫1001时,匹配的结果会放入变量 1中, 1 中 , 1=1001。
省略的“many actions”里面的内容:
<action application="set" data="dialed_extension=$1"/>
<action application="export" data="dialed_extension=$1"/>
set是将变量设置在当前Channel上,及a-leg。
export是将变量设置在b-leg上,还设置了一个特殊的值。
上面第二行相当于:
<action application="set" data="dialed_extension=$1"/>
<action application="set" data="export_vars=dialed_extension"/>
接着:
<action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<action application="bind_meta_app" data="2 b s record_session::$${recordings_dir}/${caller_id_number}.${strftime{%Y-%m-%d-%H-%M-%S}}.wav"/>
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<action application="bind_meta_app" data="4 b s execute_extension::att_xfer XML features"/>
bind_meta_app的作用是在该Channel上绑定DTMF(Dual Tone Multi Frequency(双音多频))。上面分别绑定了1、2、3、4四个按钮,都绑定在了b-leg上。
接着设置回铃音:
<action application="set" data="ringback=${us-ring}"/>
如果发生呼叫转移,听到回铃音:
<action application="set" data="transfer_ringback=$${hold_music}"/>
设置呼叫超时变量:
<action application="set" data="call_timeout=30"/>
<action application="set" data="hangup_after_bridge=true" />
<action application="set" data="continue_on_fail=true" />
<action application="hash" data="insert/${domain_name}-call_return/${dialed_extension}/${caller_id_number}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/${dialed_extension}/${uuid}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/${called_party_callgroup}/${uuid}"/>
<action application="hash" data="insert/${domain_name}-last_dial_ext/global/${uuid}"/>
最后一句:向 domainname−lastdialext这个hash表中插入一个global键,值是 d o m a i n n a m e − l a s t d i a l e x t 这 个 h a s h 表 中 插 入 一 个 g l o b a l 键 , 值 是 {uuid}。
set是将变量设置在Channel上,以通道变量形式存在,而hash保存到内存的哈希表数据结构中。
设置通道变量:
<action application="set" data="called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}"/>
哈希表中插入数据:
<action application="hash" data="insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}"/>
终于到了一个干实事的地方:
<action application="bridge" data="{sip_invite_domain=$${domain}}user/${dialed_extension}@${domain_name}"/>
呼叫字符串翻译出来就是:
{sip_invite_domain=192.168.7.2}user/[email protected]
“{}”里是设置通道变量。等价于:
<action application="export" value="nolocal:sip_invite_domain=192.168.7.2"/>
<action application="bridge" value="user/[email protected]"/>
路由完成,接下来可能有几种情况:
bridge一直阻塞,1000挂机,Dialplan没有必要执行了,产生计费信息,并销毁a-leg。
1001挂机,a-leg依然存在。
通过给continue_on_fail不同的值,决定在什么情况下继续。
<action application="set" data="continue_on_fail=USER_BUSY,NO_ANSWER"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="voicemail" data="default ${domain_name} ${dialed_extension}"/>
暂停1秒,然后转到1001的语音信箱。
<extension name="echo">
<condition field="destination_number" expression="^9196$">
<action application="answer"/>
<action application="echo"/>
condition>
extension>
<extension name="delay_echo">
<condition field="destination_number" expression="^9196$">
<action application="answer"/>
<action application="delay_echo" data="5000"/>
condition>
extension>
<extension name="nb_conferences">
<condition field="destination_number" expression="^(30\d{2})$">
<action application="answer" data=""/>
<action application="conference" data="$1-${domain_name}@default"/>
condition>
extension>
30开头的4位数字呼叫,会进入电话会议。
<action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
1000呼叫1001,1001摘机与1000通话。1001通过按“*3”这个DTMF按键触发execute_extension动作。
<extension name="cf">
<condition field="destination_number" expression="^cf$">
<action application="answer"/>
<action application="transfer" data="-both 30${dialed_extension:2} XML default"/>
condition>
extension>
transfer一行等价于:
<action application="transfer" data="-both 3001 XML default"/>
-both表示将两条腿分别转到3001这个extension上。
inline Dialplan称为内联拨号计划。
语法格式:
app1:arg1,app2:arg2,app3:arg3
originate user/1000 echo inline
originate user/1000 answer,echo inline
查看系统支持多少Dialplan
show dialplan
FreeSWITCH中有超过140个App,常用的有:
(1)set
设置一个通道变量。
(2)echo
回声。
(3)info
日志打印全部通道变量。
(4)answer
用于应答一路呼叫。
(5)bridge
负责桥接另一条腿。
(6)playback
playback用于给Channel放音。
(7)sleep
设置可以等待/暂停的一段时间。
(8)ring_ready
在SIP中给对方回180消息,通知对方可以振铃了。
(9)pre_answer
在SIP中给对方回复183消息,后续的playbakck之类的动作作为早期媒体发送给对方。
(10)read
用于实现播放声音并且等待接收DTMF按键。
(11)play_and_get_digits
与read类似,更高级。
API调用一般是通过set来执行的:
<action application="set" data="api_result=${status()}"/>
<action application="set" data="api_result=${version()}"/>
<action application="set" data="api_result=${strftime()}"/>
<action application="set" data="api_result=${expr(1+1)}"/>
给变量赋值:
<action application="set" data="my_var=my_value"/>
export可以对a-leg和b-leg同时赋值(即使此时b-leg不存在):
<action application="export" data="my_var=my_value"/>
export可以通过nolcal参数将变量限制仅复制到b-leg上:
<action application="export" data="nolocal:my_var=my_value"/>
a-leg上的一些值复制到b-leg上:
<action application="export" data="var1=$var1"/>
<action application="export" data="var2=$var2"/>
<action application="export" data="var3=$var3"/>
等价于:
<action application="set" data="export_vars=var1,var2,var3"/>
取消Variable定义只需对它赋一个特殊值–”undef“或使用unset App
<action application="set" data="var1=_undef_"/>
<action application="unset" data="var1"/>
截取Variable值
语法:${var:位置:长度}
会话初始协议(Session Initiation Protocal)是一个控制发起、修改和终结交互式多媒体会话的信令协议。
SIP是一个基于文本的协议,与HTTP和SMTP类似。
HTTP:
GET /index.html HTTP/1.1
SIP:
INVITE sip:seven@freeswitch.org.cn SIP/2.0
SIP是一个对等协议,类似P2P。
在SIP网络中,Alice和Bob都称为用户代理(User Agent,UA)。UA是在SIP网络中发起或响应SIP处理的逻辑实体。
UA是有状态的。UA有两种:一种是UAC(UA Client),发起SIP请求的一方;另一种是UAS(UA Server),接受并
发送响应的一方。一般来说,UA都会实现上述两种功能。
还有一种特殊的UA称为背靠背代理(Back-to-Back UA,B2BUA)。FreeSWITCH就是一个典型的B2BUA。
边界会话控制器(Session Border Controller,SBC)。主要位于一堆SIP服务器的边界,用于隐藏内部服务器的
拓扑结构、抵御外来攻击等。
SIP的6种基本方法
基本方法 | 说明 |
---|---|
REGISTER | 注册联系信息 |
INVITE | 初始化一个会话,可以理解为发起一个呼叫 |
ASK | 对INVITE消息的最终响应 |
CNACEL | 取消一个等待处理或正在处理的请求 |
BYE | 终止一个电话 |
OPTIONS | 查询和服务器能力,也可以用作ping测试 |
SIP还定义了一些扩展方法,如SUBSCRIBE、NOTIFY、MESSAGE、REFER、INFO等。
SIP必须包含的头域
名称 | 描述 |
---|---|
Call-ID | 用于区分不同会话的唯一标志 |
CSeq | 顺序号,用于在同一会话中区分事务 |
From | 说明请求来源 |
To | 说明请求接受方 |
Max-Forwards | 限制跳跃点数和最大转发次数 |
Via | 描述请求消息经过的路径 |
注册流程
Alice向FreeSWITCH发起注册(REGISTER)请求,FreeSWITCH返回401消息对Alice发起Challenge(挑战),Alice将自己的用户名密码信息
与收到的Challenge信息进行计算,并将计算结果以加密的形式附加到下一个REGISTER请求上,重新发起注册,FreeSWITCH收到后对本地数
据库中保存的Alice的信息使用同样的算法进行计算和加密,并将其与Alice发过来的计算结果想比较。如果计算结果匹配,则认证通过,
Alice便可以正常注册。
状态码由三位数字组成,与HTTP类似:
sip:Alice@192.168.1.20
192.168.1.9是FreeSWITCH服务器,Bob和Alice在另外机器上,Bob呼叫Alice,Bob使用使用服务器地址,
FreeSWITCH接到请求后,查找本地数据库,找到Alice实际地址,建立呼叫。
SIP负责建立和释放会话,一般来说,会话包含相关的媒体,如视频和音频。媒体数据是由SDP(Session Description Protocol,
会话描述协议)描述的。
SDP一般不单独使用,它与SIP配合使用时会放在SIP协议正文(Body)中。
媒体流的协商过程称为SOA(Service Offer and Answer,协议/应答)。
3PCC(Third Party Call Control,第三方电话呼叫控制)指得是由第三方控制者(Controller)在另外两者之间建立的一个会话,
由控制者负责会话双方的媒体协商。
在3PCC中可能没有SDP。
HTTP是用TCP承载的,而SIP则支持TCP和UDP承载。常用的SIP都是用UDP承载的。
需要对SIP加密的情况,可以使用TLS。TLS是基于TCP的。
从模拟信号变成数字信号的过程称为模数转换(Analog Digital Conver,AD)。AD转换要经过采样、量化、编码三个过程。
使用PCM方式对原始声音信号进行采样、量化后得到线性编码,然后再进行压缩,这种编码方式称为PCM编码。PCM的两种压缩
方式A率和μ率对应的编码名称分别为PCMA和PCMU。
FreeSWITCH支持非常丰富的语音编码。
控制台使用show codec
命令,可以查看FreeSWITCH支持的编码类型。
在基于SIP的通信中,媒体数据是在RTP流中传输的。
RTP包使用与SIP不同的UDP端口传送,因而在实际传输前需要先通过SIP信令与对方“协商”好往哪个端口传送。
RTP数据一般只使用UDP承载。
SIP Profile支持的媒体列表是在vars.xml文件中配置的。
<X-PRE-PROCESS cmd="set" data="global_codec_prefs=G722,PCMU,PCMA,GSM" />
<X-PRE-PROCESS cmd="set" data="outound_codec_prefs=PCMU,PCMA,GSM" />
打一个电话,如果客户端与服务端提供的编码没有交集,FreeSWITCH会返回SIP 488消息。
SIP采用Offer/Answer(请求/应答)机制来协商。请求发起的一方提供自己的编码列表,被请求的一方比较自己支持的媒体列表最终选择一种编码,
以应答方式通知请求者,然后就可以使用兼容的编码进行通信了。
媒体类型是由SDP消息描述的。
协商可分为早协商和晚协商。当呼叫到达一个SIP Profile时,即某端收到INVITE请求而未到达路由阶段时,就先行协商,称为早协商。而等到路由
阶段,到达拨号阶段再进行协商的,称为晚协商。
系统默认为晚协商。
FreeSWITCH支持如下协商策略:generous、greedy和scrooge。
在完成SIP及SDP协商后,真正的语音数据是在RTP协议中传送的。
RTP协议的全称是Real-time Transport Protocol,即及时传输协议。
实时传输控制协议(Real-time Transfer Control Protocol或 RTP Control Protocol,RTCP)是实时传输协议的一个姐妹协议。
RTCP为RTP流媒体提供信道外的控制,本省不传输数据。
FreeSWITCH是一个B2BUA,因而在桥接两条腿时,如果两条腿分别使用不同的编码,则需要
经过一个转码过程分别转换成对方需要的编码。
需要转码时,会将收到的音频数据转换成一直中间格式,称为L16。
透传:不经过转码的情况下,将从一方收到的流媒体原样传送给另一方。
媒体绕过:真正的媒体流使用点到点传输,根本不经过FreeSWITCH。
媒体代理:对RTP数据不在进行任何处理发给另一方,只改变SDP中的“c=”部分。
为了解决监听和录音问题,FreeSWITCH在媒体流路径上放了一个Media Bug。相当于水管上的一个三通。
FreeSWITCH还不支持视频编码解码,所有的视频流都是透传的。
Log、装包工具、uuid_debug_media。
Sofia的配置文件是conf/autoload_configs/sofia.conf.xml
,不过一般不修改,大部分的配置参数
实际上述文件中使用下面的预处理指令装入conf/sip_profiles
目录中的XML中的配置。
Sofia支持多个Profile,每个Profile相当于一个SIP UA。
inernal和external最大的区别就是一个运行在5060端口,另一个运行在5080端口上。
Profile中具有大量的配置参数,这些参数与具体的部署方式和呼叫流程有关。
Sofia的Profile有很多可配置参数,它们可以影响某一Profile所代表的SIP UA的行为。
inbound-bypass-media用于设置入局呼叫是否启用“媒体绕过(Bypass Media)”模式
<param name="inbound-bypass-media" value="true"/>
internal.xml与external.xml区别是internal使用的是5060端口,external使用的是5080端口。客户端往
5060端口发消息需要鉴权。而5080不需要。
FreeSWITCH需要通过外部网关向外打电话,而这个外部网关就称为Gateway。
<gateways>
<X-PRE-PROCESS cmd="include" data="external/*.xml"/>
gateways>
<gateway name="gwl">
<param name="realm" value="SIP服务器地址"/>
<param name="username" value="SIP用户名"/>
<param name="password" value="密码"/>
gateway>
mod_sofia提供了一个API命令–sofia。
freeswitch> sofia status profile internal
freeswitch> sofia status profile internal reg
freeswitch> sofia status profile internal reg 1000
freeswitch> sofia status profile internal user 1000
freeswitch> sofia status gateway gwl
Profile相关的命令都是针对Profile进行的操作。
freeswitch> sofia profile internal start # 启动
freeswitch> sofia profile internal stop # 停止
freeswitch> sofia profile internal restart # 重启
重读sofia的配置(不是所有配置参数都能生效)
freeswitch> sofia profile internal rescan
FreeSWITCH内置了Homer Capture Agent用于SIP抓包。
使用Capture功能前,需要在sofia.conf.xml中配置Capture Node的地址。
<param name="capture-server" value="udp:192.168.0.100:6060"/>
打开和关闭全局SIP消息跟踪
freeswitch> sofia global siptrace on
freeswitch> sofia global siptrace off
打开和关闭全局SIP捕获(Homer方式抓包):
freeswitch> sofia global capture on
freeswitch> sofia global capture off
更低级别调试器
freeswitch> sofia loglevel all 9
修改Profile参数需要重启,能不重启就不重启,但IP地址相关的参数和端口,一般需要重启。
适当地解决在NAT网络环境下的内、外网通信问题,就称为NAT穿越。
NAT有三种类型:静态NAT(Static NAT)、动态NAT(Pooled NAT)和网络地址端口转换
(Network Address Port Translation,NAPT)。
NAPT有四种类型
(1)Full Cone NAT(全锥型NAT)
内部主机向外打一个洞,外网的任何主机都可以利用这个洞与它通信。
(2)Restricted Cone NAT(限制锥型NAT)
内部主机向外某一外部主机打一个洞后,只有该外部主机才能利用这个洞。
(3)Port Restricted Cone NAT(端口限制锥型NAT)
内部主机向外部主机上某一程序(一个端口)打了一个洞,只有该程序可以利用这个洞。
(4)Symmetric NAT(对称型NAT)
对称型NAT相当于对同一内部主机联系不同外部主机时都需要打不同的洞。
FreeSWITCH一般有三种拓扑结构。
客户端A–NAT–Internet–FreeSWITCH–外部网关
客户端A–FreeSWITCH–NAT–Internet–外部网关
客户端A–FreeSWITCH–NAT–Internet–外部网关(其中Internet有分支 客户端B–Internet–NAT–客户端C )
解决NAT问题通常2种思路:
解决NAT穿越问题前,先做如下准备:
发现问题、定位问题、分析问题、解决问题。
分断调试,查看日志。
tcpdump是经典的抓包工具。
# tcpdump -np -s 0 -A -vvv eth0 port 5060
tshark是Wireshark的命令行版。使用方法与tcpdump类似。
ngrep也是一个非常好用的抓包工具(类似与经典的UNIX命令行工具grep)。
# ngrep -p -q -W byline port 5060
pcapsipdump能将不同通话IP包存到不同的文件里,有大量通话的时候比较好用。
pcapsipdump -i eth0 -d /tmp/sipdump/
图形界面的抓包工具Wireshark。
_USAGE:|&name>(app_sec)[][[cid_ name][cid_num][ ]]
freeswitch> originate user/1000 &echo
freeswitch> originate user/1000 1001 XML public
主叫名称(cid_name,Caller ID Name)和主叫号码(cid_number,Caller ID Number)
freeswitch> originate user/1000 &echo XML default 'Seven Du' 7777
最后一个参数是超时的秒数。
freeswitch> originate sofia/internal/1000@192.168.100.100 &ehco XML default 'Seven Du' 7777 10
解决阻塞:
freeswitch> bgapi originate user/1000 &echo
通道变量可以影响呼叫行为。
freeswitch> originate {originate_call_id_name='Seven Du',origination_caller_id_number=7777}user/1000 &echo
有些Early Media对我们没有意义,如我们主动外呼的应用,可以指定ignore_earlly_media变量,忽略对方返回的
Early Media。
freeswitch> originate user/1000 &bridge(user/1000)
freeswitch> originate {transfer_ringback=local_stream://moh}user/1000 &bridge(user/1001)
freeswitch> originate {originate_caller_id_number=7777}user/1000 &echo
SIP发送请求到5060端口->UAS对INVITE进行鉴权->路由->找到1001实际位置->作为UCA给1001发送请求
开发FreeSWITCH的GUI有两种方法:
FusionPBX是使用PHP开发的FreeSWITCH GUI。通过将数据储存在数据库中,并修改本地XML配置文件。
2600Hz团队开发的一款开源GUI产品。
freeswitch> load_mod_xml_rpc
http://localhost:8080/partal/
# sed -e "s/1000/1020" 1000.xml > 1020.xml
script/perl
中的add_user脚本IVR(Interactive Voice Response,交互式语音响应)
IVR系统默认的配置文件为conf/autoload_config/ivr.conf.xml
。
真正的菜单配置信息放到一对“”标签中。
<entry action="menu-exec-app" digits="1" param="bridge sofia/$${domain}/[email protected]"/>
<entry action="menu-exec-app" digits="2" param="transfer 9196 XML default"/>
<entry action="menu-exec-app" digits="3" param="transfer 9664 XML default"/>
<entry action="menu-exec-app" digits="4" param="transfer 9191 XML default"/>
<entry action="menu-exec-app" digits="5" param="transfer 1234*256 enum"/>
<entry action="menu-exec-app" digits="6" param="demo_ivr_submenu"/>
<extension name="time_base_ivr">
<condition wday="2-6" hour="8:30-17:30">
<action application="ivr" data="ivr_day"/>
<anti-anction application="ivr" data="ivr_night"/>
condition>
extension>
默认声音文件存放在sounds目录下面,英文。
最简单的方式就是将语音包直接替换成中午语音包。
使用sound_prefix变量定义声音文件的具体路径
<X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/en/us/callie"/>
为了屏蔽各种不同语言提示的差异性,FreeSWITCH实现了Phrase(短语)框架。
中文与英文的配置大同小异,将英文复制一份,并在此基础上进行修改。
可以通过一些预先录制的声音文件“说”出一些常用的词语组合。
准备就绪后,再Dialplan中指定language或default_language通道变量。
originate user/1000 &record(/tmp/welcome.wav)
<extension name="record">
<condition field="destination_number" expression="^rec(.*)$">
<action application="answer"/>
<action application="playback" data="tone_stream://%(100,1000,800)"/>
<action application="record" data="/tmp/$1.wav"/>
condition>
extension>
uuid_record <channel_uuid> start /tmp/record.wav
该录音文件包含两个声道。
可以使用sox命令进行混音:
$ sox record.wav -c 1 record-1.wav
在Dialplan中,可以通过record_session达到类似的效果:
<extension name="record">
<condition field="destination_number" expression="^(100[0-9])$">
<action application="record_session" data="/tmp/record-$1.wav"/>
<action application="bridge" data="user/$1"/>
condition>
extension>
record_session是一个APP,非阻塞。
通过事先将RECORD_STEREO通道变量设置为true可以在录音时直接录成立体声。
为了最大限度地节省系统资源,可以将声音录制成原生(Native)格式。
freeswitch> originate user/1000 &record(/tmp/test)
会将录音录成/tmp/test.PCMU
可以使用sox软件中的play命令播放
play -e u-law -r 8000 -t raw test-in.PCMU
大部分声音文件的支持都在mod_sndfile模块中实现的。典型的如WAV、AU、AIFF、VOX等。
local_stream是在mod_local_stream中实现的。
silence_stream是一个静音流。
<action application="playback" data="silence_stream://2000,1400"/>
1400为舒适噪音的参数值。
tone_stream是一个铃流,它在mod_tone_stream模块中实现。
我国的回铃音信号为450Hz的信号音,1秒通,4秒断。
<action application="playback" data="tone_stream://%(1000,4000,450)"/>
可以将多个文件串联起来,放在同一个playback命令中播放。
<action application="playback" data="file_string:///tmp/file1.wav!tmp/file2.wav!/tmp/file3.wav"/>
不断播放test.wav直至挂机的实现如下:
<action application="endless_playback" data="temp/test.wav"/>
<action application="say" data="en number iterated 1234"/>
TTS(Text To Speech)是将文本转换成语音的一项技术,因而又称为语音合成(Synthesis)。
mod_file是基于Flite语音合成引擎的一个TTS模块。
originate user/1000 &speak('flite|kal|Hello,Welcome to FreeSWITCH')
可以使用命令来执行TTS功能。mod_tts_commandline模块可以调用这些命令,生成一个文件,进而
播放这个声音文件,从而达到其他TTS软件执行TTS功能的目的。
MRCP(Media Resource Control Protocl)是一个支持访问网络上的媒体资源的协议。
它的典型应用就是TTS和ASR(自动语音识别)。
Google Translate(谷歌翻译)
<action application="bridge" data="user/${dialed_extension}@${domain_name}"/>
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
使用if..then..else之类的逻辑选择播放声音,其他一律播放同一个文件。
使用Phrase Macro功能实现各种提示
<include>
<macro name="USER_BUSY">
...
macro>
<macro name="USER_NOT_REGISTERED">
...
macro>
include>
在被叫失败后播放我们上面指定的提示音或TTS是有一个前提的,在Dialplan的第一个bridge要有以下两行
<action application="set" data="hangup_after_bridge=true"/>
<action application="set" data="continue_on_fail=true"/>
通过拨打一个特定功能码登记预转移到的电话号码,以后所有呼叫都会转移到该号码上。
ACD(Auto Call Distribution,自动电话分配)
在电话分配中,一般用停泊与取回的方式进行电话搭接。
fifo是一个“生产者–消费者”模型,即来话(Caller)相当于生产者(Producer),坐席(Agent)
则称为消费者(Consumer),它对来话进行服务相当于“消费”生产者生产的内容。
mod_fifo的配置文件是conf/autoload_configs/fifo.conf.xml
。
Dialplan将来路电话路由到我们配置的fifo。
mod_fifo提供了一个fifo_member命令可以动态增加和删除座席。
offhook(摘机)座席,这种座席会事先呼入队列并等待。
许多相关的通道变量可以改变它的行为。有效的使用这些变量,往往能配置出比较实用的功能。
当fifo相关状态发生变化时,会产生一些Subclass为fifo::info的CUSTOM事件。
mod_callcenter采用一种基于积分(score)策略的排队算法。
# make mod_callcenter-install
freeswitch> load mod_callcenter
默认配置文件是conf/autoload_configs/callcenter.conf.xml
。
mod_callcenter提供了一个callcenter_config的API命令,用于管理与该模块相关的资源。
mod_callcenter也支持offhook座席。
FreeSWITCH内部使用关系型数据库记录一些实时的数据。
默认使用SQLite嵌入式数据库。
mod_sofia模块中每一个Profile都使用一个单独的数据库。
其他模块也有自己的数据库。
SQLite在并发量特别大的情况下会是一个瓶颈。
在编译前安装unixODBC的开发包,并安装相关的数据驱动。
安装MyODBC。
FreeSWITCH内部对PostgreSQL原生支持。
如果需要支持视频呼叫,只需要在配置文件中增加相关的视频编解码就可以了。
FreeSWITCH中实现了一个简单的mod_fsv模块,提供录像及回放支持。
通过相应的视频库或硬件的DSP芯片,也可以在FreeSWITCH中提供视频的转码。
mod_cdr_csv模块可以记录CSV格式的话单。
通过mod_cdr_csv模块可以直接在FreeSWITCH中将话单写入PostgreSQL数据库。
支持将话单写入远程的HTTP服务器。
mod_nibblebill是一个预付费的计费模块。
启动多个不同端口FreeSWITCH实例。
Doubango是一个不错的开源框架,跟电信业务走得比较近。
如果要通过互联网与运营商的IMS对接,就需要通过SBC及层层防火墙。可以将SBC设备和IMS看成
SIP转PSTN的“大网关”。
H.323是比较古老的VoIP协议,然而现在还是有很多设备支持该协议。
来电转接和代接是企业PBX中常用的功能。来电转接分为盲转和协商转。
代接一般用于工位上没有人其他工位上的人代为接听的场景。
共享线路呈现(Shared Lines Appearence,SLA)也是企业应用中非常有用的功能。
模拟话机中没有,只有SIP话机才能实现该功能。可以在自己话机上监视其他话机状态。
实现该业务模式最经济的方式就是使用组播(Multicast,或称多播)。组播只想向组播
地址发送一个RTP流,而监听该组播地址的所有主机就能收到。
DTMF(Double Tone Multiple Frequency,双音多频)是一种通话过程中的号码传输方式,
特别是在IVR类应用中,一般的电话菜单都是通过案件控制的。
运营商一般不提供SIP对开中继的方式,而是开发单个的接入号码。
连接TMD传真机最简单的方式是使用一个模拟转SIP的网关,将它变成SIP后在FreeSWITCH中收发
传真就变得容易了。
多租户就是在一个系统中(或更简单点,一台FreeSWITCH服务器上),支持多个彼此相互独立的
PBX应用,这些不同的PBX中可能有相同的分机号,而不会产生冲突。
考虑在用originate外呼的时候也使用Dialplan。使用一个新的Endpoint,称为loopback。
HA(High Availability)即高可用(可靠)性。
HP(High Performance),即高性能。
FreeSWITCH支持使用嵌入式的脚本语言控制呼叫流程。
可支持:
Lua语法优雅,小巧。
与嵌入式语言不通,通过Event Socket方式,可以使用运行在FreeSWITCH外部的
程序控制FreeSWITCH。
FreeSWITCH使用SWIG来支持多语言。
ESL是一个客户端,它主要对FreeSWITCH进行逻辑控制。
《FreeSWITCH权威指南》