前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Freeswitch的语音视频通话

基于Freeswitch的语音视频通话

作者头像
obaby
发布2023-02-22 11:11:48
4.2K0
发布2023-02-22 11:11:48
举报
文章被收录于专栏:obaby@mars

之前写过一篇《阿里云 opensips nat内网穿透》,当时是为了解决对讲机视频对讲的问题。但是之前的方案存在一个问题,那就是虽然服务器能够正常提供服务。但是在接通之后如果设备不在同一个局域网内就会导致有音频但是没有视频信息。这个问题困扰了很久,直到现在算是能够解决这个问题。出现上面这个问题的根本原因在于设备的网络层次关系太过复杂,视频信息没有办法透传。我不是语音视频方面的专家,集中nat结构我也不在叙述了,感兴趣的访问这个链接:https://www.cnblogs.com/zhumengke/articles/11204924.html

要实现视频信息穿透,可以采用ice方式,对应的服务端可以使用stunman(https://github.com/jselbie/stunserver).

Features: Compliant with the latest RFCs including 5389, 5769, and 5780. Also includes backwards compatibility for RFC 3489. Supports both UDP and TCP on both IPv4 and IPv6. Client test app provided. Stun server can operate in “full” mode as well as “basic” mode. Basic mode configures the server to listen on one port and respond to STUN binding requests. Full mode configures the service to listen on two different IP address interfaces (if available) and provide NAT behavior and filtering detection support for clients. Support for running a full mode STUN service on an Amazon EC2 instance. Run “stunserver –help” for visit www.stunprotocol.org on how to configure this mode. Open source Apache license. See LICENSE file fore more details. ———————————————————

可以通过源码编译的方式进行安装:

代码语言:javascript
复制
Debian/Ubuntu/Mint
     sudo apt-get install g++
     sudo apt-get install make
     sudo apt-get install libboost-dev # For Boost
     sudo apt-get install libssl-dev # For OpenSSL

安装之后通过下面的命令启动:

代码语言:javascript
复制
./stunserver --mode full --primaryinterface 47.*.*.4 --altinterface  172.18.99.29  --verbosity 3

Freeswitch可以通过docker安装,或者源码编译:

1.docker地址:https://hub.docker.com/r/safarov/freeswitch

2.源码安装网上的安装文章也比较多了,可以搜索即可。

安装完成之后修改vars.xml文件:

代码语言:javascript
复制
vim /usr/local/freeswitch/conf/vars.xml 
代码语言:javascript
复制
<X-PRE-PROCESS cmd="set" data="global_codec_prefs=OPUS,G722,PCMU,PCMA,H263,H264,VP8"/>
 <X-PRE-PROCESS cmd="set" data="outbound_codec_prefs=OPUS,G722,PCMU,PCMA,H263,H264,VP8"/>

 <!--
     xmpp_client_profile and xmpp_server_profile
     xmpp_client_profile can be any string.
     xmpp_server_profile is appended to "dingaling_" to form the database name
     containing the "subscriptions" table.
     used by: dingaling.conf.xml enum.conf.xml
 -->

 <X-PRE-PROCESS cmd="set" data="xmpp_client_profile=xmppc"/>
 <X-PRE-PROCESS cmd="set" data="xmpp_server_profile=xmpps"/>
 <!--
      THIS IS ONLY USED FOR DINGALING

      bind_server_ip

      Can be an ip address, a dns name, or "auto".
      This determines an ip address available on this host to bind.
      If you are separating RTP and SIP traffic, you will want to have
      use different addresses where this variable appears.
      Used by: dingaling.conf.xml
 -->
 <X-PRE-PROCESS cmd="set" data="bind_server_ip=auto"/>

 <!-- NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE

      If you're going to load test FreeSWITCH please input real IP addresses
      for external_rtp_ip and external_sip_ip
 -->

 <!-- external_rtp_ip
      Can be an one of:
          ip address: "12.34.56.78"
          a stun server lookup: "stun:stun.server.com"
          a DNS name: "host:host.server.com"
      where fs.mydomain.com is a DNS A record-useful when fs is on
      a dynamic IP address, and uses a dynamic DNS updater.
      If unspecified, the bind_server_ip value is used.
      Used by: sofia.conf.xml dingaling.conf.xml
 -->
 <X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=47.*.*.4"/>

 <!-- external_sip_ip
     Used as the public IP address for SDP.
      Can be an one of:
          ip address: "12.34.56.78"
          a stun server lookup: "stun:stun.server.com"
          a DNS name: "host:host.server.com"
      where fs.mydomain.com is a DNS A record-useful when fs is on
      a dynamic IP address, and uses a dynamic DNS updater.
      If unspecified, the bind_server_ip value is used.
      Used by: sofia.conf.xml dingaling.conf.xml
 -->
 <X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=47.*.*.4"/>

修改external_sip_ip external_rtp_ip 为服务器公网ip,修改global_codec_prefs outbound_codec_prefs添加H263,H264,VP8,重新启动服务即可。

在客户端中开启stun服务器:

此时再通过linphone拨打视频电话就可以看到视频了:

并且可以看到Ice status 为In progress。这就说明ice服务生效了。

添加用户可以通过下面的命令:

代码语言:javascript
复制
perl scripts/perl/add_user 1021

添加之后通过raloadxml使用户信息生效:

代码语言:javascript
复制
./fs_cli -x reloadxml

添加账号之后会发现超过1100之后的号码都无法进行呼叫,需要修改拨号计划:

代码语言:javascript
复制
root@opensips:/usr/local/freeswitch/conf/dialplan# vim default.xml

删除以下内容:

代码语言:javascript
复制
 <!--
        Snom button demo, call 9000 to make button 2 mapped to transfer the current call to a conference
    -->

    <extension name="snom-demo-2">
      <condition field="destination_number" expression="^9001$">
        <action application="eval" data="${snom_bind_key(2 off DND ${sip_from_user} ${sip_from_host} ${sofia_profile_name} message notused)}"/>
        <action application="transfer" data="3000"/>
      </condition>
    </extension>

    <extension name="snom-demo-1">
      <condition field="destination_number" expression="^9000$">
        <!--<key> <light> <label> <user> <host> <profile> <action_name> <action>-->
        <action application="eval" data="${snom_bind_key(2 on DND ${sip_from_user} ${sip_from_host} ${sofia_profile_name} message api+uuid_transfer ${uuid} 9001)}"/>
        <action application="playback" data="$${hold_music}"/>
      </condition>
    </extension>

    <extension name="eavesdrop">
      <condition field="destination_number" expression="^88(\d{4})$|^\*0(.*)$">
        <action application="answer"/>
        <action application="eavesdrop" data="${hash(select/${domain_name}-spymap/$1$2)}"/>
      </condition>
    </extension>

    <extension name="eavesdrop">
      <condition field="destination_number" expression="^779$">
        <action application="answer"/>
        <action application="set" data="eavesdrop_indicate_failed=tone_stream://%(500, 0, 320)"/>
        <action application="set" data="eavesdrop_indicate_new=tone_stream://%(500, 0, 620)"/>
        <action application="set" data="eavesdrop_indicate_idle=tone_stream://%(250, 0, 920)"/>
        <action application="eavesdrop" data="all"/>
      </condition>
    </extension>

    <extension name="call_return">
      <condition field="destination_number" expression="^\*69$|^869$|^lcr$">
        <action application="transfer" data="${hash(select/${domain_name}-call_return/${caller_id_number})}"/>
      </condition>
    </extension>

    <extension name="del-group">
      <condition field="destination_number" expression="^80(\d{2})$">
        <action application="answer"/>
        <action application="group" data="delete:$1@${domain_name}:${sofia_contact(${sip_from_user}@${domain_name})}"/>
        <action application="gentones" data="%(1000, 0, 320)"/>
      </condition>
    </extension>
<extension name="add-group">
      <condition field="destination_number" expression="^81(\d{2})$">
        <action application="answer"/>
        <action application="group" data="insert:$1@${domain_name}:${sofia_contact(${sip_from_user}@${domain_name})}"/>
        <action application="gentones" data="%(1000, 0, 640)"/>
      </condition>
    </extension>

    <extension name="call-group-simo">
      <condition field="destination_number" expression="^82(\d{2})$">
        <action application="bridge" data="{leg_timeout=15,ignore_early_media=true}${group(call:$1@${domain_name})}"/>
      </condition>
    </extension>

    <extension name="call-group-order">
      <condition field="destination_number" expression="^83(\d{2})$">
        <action application="bridge" data="{leg_timeout=15,ignore_early_media=true}${group(call:$1@${domain_name}:order)}"/>
      </condition>
    </extension>

    <extension name="extension-intercom">
      <condition field="destination_number" expression="^8(10[01][0-9])$">
        <action application="set" data="dialed_extension=$1"/>
        <action application="export" data="sip_auto_answer=true"/>
        <action application="bridge" data="user/${dialed_extension}@${domain_name}"/>
      </condition>
    </extension>

修改以下内容:

代码语言:javascript
复制
<!-- If sip_req_host is not a local domain then this has to be an external sip uri -->
   <!--
   <extension name="external_sip_uri" continue="true">
     <condition field="source" expression="mod_sofia"/>
     <condition field="${outside_call}" expression="^$"/>
     <condition field="${domain_exists(${sip_req_host})}" expression="true">
       <anti-action application="bridge" data="sofia/${use_profile}/${sip_to_uri}"/>
     </condition>
   </extension>
   -->
   <!--
       Snom button demo, call 9000 to make button 2 mapped to transfer the current call to a conference
   -->


   <!--
        dial the extension (1000-1019) for 30 seconds and go to voicemail if the
        call fails (continue_on_fail=true), otherwise hang up after a successful
        bridge (hangup_after_bridge=true)
   -->
   <extension name="Local_Extension">
     <condition field="destination_number" expression="^([1-9][0-9]*)$"> <!-- 主要修改此处正则表达式,去掉前面的各种附加条件 -->
       <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="transfer_ringback=$${hold_music}"/>
       <action application="set" data="call_timeout=30"/>
       <!-- <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"/>
       <action application="sleep" data="1000"/>
       <action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>
     </condition>
   </extension>

linphone安卓版本下载地址:https://www.linphone.org/releases/android/

参考链接:

Version 1.2. This is the source code to STUNTMAN – an open source STUN server and client code by john selbie. Compliant with the latest RFCs including 5389, 5769, and 5780. Also includes backwards compatibility for RFC 3489. Compiles on Linux, MacOS, BSD, Solaris, and Win32 with Cygwin. Windows binaries avaialble from www.stunprotocol.org. https://github.com/jselbie/stunserver 319 forks. 1,199 stars. 9 open issues.

Recent commits:

https://freeswitch.org/confluence/display/FREESWITCH/NAT+Traversal

https://hub.docker.com/r/safarov/freeswitch

https://www.linphone.org/releases/android/

https://freeswitch.org/confluence/display/FREESWITCH/NAT+Traversal#NATTraversal-UsingSTUNtoaidinNATTraversal

☆文章版权声明☆

* 网站名称:obaby@mars * 网址:https://h4ck.org.cn/ * 本文标题: 《基于Freeswitch的语音视频通话》 * 本文链接:https://h4ck.org.cn/2021/10/%e5%9f%ba%e4%ba%8efreeswitch%e7%9a%84%e8%af%ad%e9%9f%b3%e8%a7%86%e9%a2%91%e9%80%9a%e8%af%9d/ * 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年10月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档