Introduction
本篇文章笔者将介绍一种简单的基于 SIP 协议的 VoIP 电话网络系统的搭建。我们这次搭建的并不是传统意义上的使用程控交换机操作的双芯铜线座机电话网络(也称 PSTN,公共交换电话网络),而是一种网络IP电话网络。
这里先解释以下问题:
What is a switch?
交换机,就像一个不知疲倦的高效率的接线员一样,当A发起到B的通讯请求时,本“接线员”就将A->B的链路接到一起,使A与B之间可以互相交流。
Why VoIP?
大家肯定都注意到,移动早在去年推出了在纯 4G 分组数据网络上的高清通话(VoLTE),而电信在家家户户升级光纤,拆除进户电话线后,传统的固话竟然直接接在ONU设备(光猫)上。这一切的背后到底是人性的扭曲还是道德的沦丧?啊呸呸呸,不论是 VoLTE,VoWiFi,电信光猫上的语音功能,他们的本质都是一个,VoIP,即在承载网络上传输语音数据。所以 VoLTE 就是在 LTE 接入的网络中传递语音(而不需要回落到类似PSTN的传统2G的电路交换,上网通话都在 4G 环境下),VoWiFi 就是在现有 Wi-Fi 环境下,利用 Wi-Fi 网络来传递语音。现代电话采用IP网络来作为载体是一种明显的趋势,满足了现在人们对快速高清通话、富媒体传输的需要。
QQ的语音平台模型可能比较容易解释这套系统:张三通过QQ语音服务器联系上了李四,像这样: 张三 <–> QQ语音服务器 <–> 李四
Related Communication Protocols
以上提到的几乎所有现代电话通信方式,其本质大都是基于 SIP 协议实现的 VoIP 。而整个这样一套接入控制系统,也称 IMS。
SIP:(Session Initiation Protocol,会话初始协议)是由IETF(Internet Engineering Task Force,因特网工程任务组)制定的多媒体通信协议。它是一个基于文本的应用层控制协议,用于创建、修改和释放一个或多个参与者的会话。是 VoIP 系统中最主要的协议,通话前期它控制信令(如拨号给张三)的传播,并维护后期的数据传输通道。
IMS:(IP Multimedia Subsystem)IP多媒体子系统,是对上述 VoIP 接入控制交换这一套系统的总称。
具体定义这不阐述,自行G一下。
Set-up Platforms
任意常见的操作系统平台,类 Unix/Windows 都可以,所以本套电话网络可以搭建在树莓派上!
核心软件:FreeSWITCH (免费开源,超强大的说)
笔者提示:本软件可以在官方网站上获取源代码与预编译好的二进制代码。编译完成后,可以使用 FreeSWITCH.exe / fs_cli 来启用控制台。在默认情况下, FreeSWITCH 提供了 1000-1019 这一些默认帐号可以提供测试目的的使用。下面,笔者将介绍 FreeSWITCH 的重要配置目录与文件。
conf/dialplan:这里就是拨号规则的配置文件夹。其中包含默认拨号规则文件 (default.xml)。通过修改这些文件可以实现拨号行为的调整。
下面是对其中一规则的摘录:
<extension name="Local_Extension"> <!-- 拨号规则名称 --> <!-- 目的号码匹配规则,支持使用正则表达式 --> <condition field="destination_number" expression="^(10[01][0-9])$"> <!-- 匹配 1000-1019 --> <action application="export" data="dialed_extension=$1" /> <!-- bind_meta_app can have these args <key> [a|b|ab] [a|b|o|s] <app> --> <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" /> <!-- 接通提示音(“嘟”声,美标) --> <!-- <action application="set" data="ringback=${us-ring}"/> --> <!-- 可以自定义音乐,达到“彩铃”的效果 --> <action application="set" data="ringback=${sounds_dir}/RINGBACK.wav" /> <action application="set" data="transfer_ringback=$${hold_music}" /> <action application="set" data="call_timeout=60" /> <!-- <action application="set" data="sip_exclude_contact=${network_addr}"/> --> <action application="set" data="hangup_after_bridge=true" /> <!-- 在以下出错情况下继续 --> <action application="set" data="continue_on_fail=NORMAL_TEMPORARY_FAILURE,USER_BUSY,NO_ANSWER,TIMEOUT,NO_ROUTE_DESTINATION" /> <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="set" data="called_party_callgroup=${user_data(${dialed_extension}@${domain_name} var callgroup)}" /> <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}" /> <!--<action application="export" data="nolocal:rtp_secure_media=${user_data(${dialed_extension}@${domain_name}var rtp_secure_media)}"/> --> <action application="hash" data="insert/${domain_name}-last_dial/${called_party_callgroup}/${uuid}" /> <!-- 将呼入的电话桥接至本交换域中的用户(即:将拨叫方与被叫方连接起来) --> <action application="bridge" data="user/${dialed_extension}@${domain_name}" /> <!-- 告知拨叫方对方已经摘机 --> <action application="answer" /> <!-- 延迟1秒 --> <action application="sleep" data="1000" /> <!-- 如果拨号过程发生错误,且错误能继续往下处理,则执行以下流程 --> <!-- FreeSWITCH 自带的语音信箱功能(比如语音留言) --> <!-- <action application="bridge" data="loopback/app=voicemail:default${domain_name} ${dialed_extension}"/> --> <!-- 播放提示音、提示语(比如正在通话中,未接听等) --> <action application="playback" data="${sounds_dir}/BEGIN.wav" /> <action application="playback" data="${originate_disposition}.wav" /> </condition> </extension>
上面演示了 FreeSWITCH 在拨号时的处理流程。
conf/directory/default:这里存放了本交换机中用户的配置文件。例如:
<include> <user id="1002"> <!-- 用户名(电话号码) --> <params> <param name="password" value="$${default_password}" /> <!-- 该用户(话机)向本交换机注册时使用的密码,这里使用默认密码 --> <param name="vm-password" value="1002" /> </params> <variables> <variable name="toll_allow" value="domestic,international,local" /> <variable name="accountcode" value="1002" /> <!-- 用户名(电话号码) --> <variable name="user_context" value="default" /> <!-- 用户上下文 --> <variable name="effective_caller_id_name" value="Extension 1002" /> <!-- 用户名称(友好地显示) --> <variable name="effective_caller_id_number" value="1002" /> <!-- 用户电话号码(友好地显示) --> <variable name="outbound_caller_id_name" value="$${outbound_caller_name}" /> <variable name="outbound_caller_id_number" value="$${outbound_caller_id}" /> <variable name="callgroup" value="techsupport" /> </variables> </user> </include>
conf/vars.xml:这是 FreeSWITCH 的变量主要配置文件。下面摘录一些重要的配置项:
<X-PRE-PROCESS cmd="set" data="default_password=XXX" /> <!-- 定义用户的默认密码 --> <X-PRE-PROCESS cmd="set" data="sound_prefix=$${sounds_dir}/en/us/callie" /> <!-- 定义声音文件的目录 --> <!-- 设定内部(internal)/外部(external)的IP与域名称。FreeSWITCH 在启动时会自动获取网络情况与IP信息,甚至可以自动做 UPnP 映射来实现内网穿透。 --> <X-PRE-PROCESS cmd="set" data="external_sip_ip=$${local_ip_v4}" /> <X-PRE-PROCESS cmd="set" data="external_rtp_ip=$${local_ip_v4}" /> <X-PRE-PROCESS cmd="set" data="internal_sip_ip=X.X.X.X" /> <X-PRE-PROCESS cmd="set" data="internal_rtp_ip=X.X.X.X" /> <X-PRE-PROCESS cmd="set" data="domain=$${local_ip_v4}" /> <X-PRE-PROCESS cmd="set" data="domain_name=$${domain}" /> <!-- SIP监听的端口号 / SSL 通讯设置。 --> <!-- Internal SIP Profile --> <X-PRE-PROCESS cmd="set" data="internal_auth_calls=true" /> <X-PRE-PROCESS cmd="set" data="internal_sip_port=5060" /> <X-PRE-PROCESS cmd="set" data="internal_tls_port=5061" /> <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false" /> <!-- External SIP Profile --> <X-PRE-PROCESS cmd="set" data="external_auth_calls=false" /> <X-PRE-PROCESS cmd="set" data="external_sip_port=5080" /> <X-PRE-PROCESS cmd="set" data="external_tls_port=5081" /> <X-PRE-PROCESS cmd="set" data="external_ssl_enable=false" />
Available Clients:
现在各大平台都有可以使用的SIP客户端软件。笔者这里推荐几款:X-Lite(Windows,免费),JusVoIP(Android&iOS,免费),Mac 下同样在 App Store 里有很多可选的客户端。
写得不错,持续关注中?
写得不错,持续关注中?
如果有公网IP就好了,可以搞到你的腾讯云上,给你的朋友们分享一下
如果搞到Android手机上,能利用手机网络通话的话,扩展性就强了很多
不过现阶段通话几乎都免费,没有搞这个的动力了
在TX云上试过,效果不错。不过很多国外IP会进来扫帐号,很是麻烦…
你可以了解一下VOS和Asterisk
如果有公网IP就好了,可以搞到你的腾讯云上,给你的朋友们分享一下
如果搞到Android手机上,能利用手机网络通话的话,扩展性就强了很多
不过现阶段通话几乎都免费,没有搞这个的动力了
在TX云上试过,效果不错。不过很多国外IP会进来扫帐号,很是麻烦…
你可以了解一下VOS和Asterisk