《FreeSWITCH参考手册》

1.21 mod_verto

上一节,我们讲了mod_rtcmod_rtc是一个纯媒体的模块,目的是为了支持WebRTC。然而,任何的通信都需要一定的信令支持,mod_verto就是配合mod_rtc的信令模块。

众所周知,WebRTC从诞生的第一天起就只定义了媒体的交互和传输,而把信令留给大家自己实现,以便有更大的自由度。最初,大部分WebRTC的例子都是基于GAE的,但在电信的VoIP领域,SIP还是占统治地位的,因而,包括FreeSWITCH在内,又有一些SIP代理和软交换设备实现了配合WebRTC使用的SIP信令,这但是SIP over WebSocket。FreeSWITCH对SIP over WebSocket的支持是直接扩展了Sofia-SIP协议栈。

但无论如何,虽然SIP与传统的VoIP协议如H323相比,脱离了老式的电信信令思维,采用了类似HTTP协议的文本协议,但,它从电信领域诞生的基因决定了它还是很难融入互联网,退一步讲,人们还是认为SIP通信专业性太强了,SIP就是SIP,互联网就是互联网。

单从协议内容角度讲,SIP对于浏览器尤其是对于移动浏览器来说,还是有些庞大了。而基于文本的SIP协议解析起来对浏览器来说,即使不是一种负担,也不是非常的优雅。对浏览器来说,最适合的数据格式是JSON已是不争的事实。

我们很高兴地看到,FreeSWITCH团队开放了mod_verto。它采用了JSON及JSON-RPC相关的信令协议,非常优雅的与mod_rtc相配合,将热闹的互连网与冷冰冰的SIP通信结合在了一起。也就是说,FreeSWITCH不再是互联网从业者眼里专业的运动员,而跟MySQL,Apache一样,可以实实在在的融入互联网了。

在WebRTC设计之初,就非常重视安全问题,因而,一切都是加密的,不管是在媒体层还是在信令层,这是个好事,唯一比较麻烦的是,对于没有耐心的实践者来说,你在跑通mod_verto前要设置好你的Web服务器以及证书。

除了Endpoint功能外,mod_verto其实还自己带了一个HTTP/HTTPS服务器。这是一个隐藏选项,下面,我们看一下其配置:

<vhosts>
    <vhost domain="localhost">
        <param name="alias" value="seven.local freeswitch.org"/>
        <param name="root" value="/usr/local/freeswitch/htdocs"/>
        <param name="script_root" value="/usr/local/freeswitch/scripts"/>
        <param name="index" value="index.html"/>
    <!--
        <param name="auth-realm" value="FreeSWITCH"/>
        <param name="auth-user" value="freeswitch"/>
        <param name="auth-pass" value="rocks"/>
    -->

    <rewrites>
        <rule expression="^/api" value="/my_custom_api.lua"/>
        <rule expression="^/channels" value="/rest.lua"/>
    </rewrites>
</vhost>

在上述配置中,alias其实没什么用,备以后扩展;root要指向Web服务的根目录;index是默认的首页;auth-相关的是HTTP Basic认证;rewrites会重写请求地址,比如把请求重定向到一个Lua脚本进行处理(类似传统的CGI)。

把上述配置加到Verto的Profile部分,就可以有一个内置的小型的HTTP服务器了。

下面的Lua脚本可以提供REST风格的API,读者请参考 https://freeswitch.org/confluence/display/FREESWITCH/Restful 自行解析:

    --[[
    Restful by Seven Du.

    GET    /channels
    GET    /channels/uuid
    POST   /channels
    PUT    /channels/uuid
    DELETE /channels/uuid
    DELETE /channels
    ]]

    function headers()
        stream:write("HTTP/1.0 200 OK\r\n")
        if (accept == "application/json") then
            stream:write("Content-Type: application/json\r\n")
        else
            stream:write("Content-Type: text/plain\r\n")
        end
        stream:write("\r\n")
    end

    -- print(env:serialize())

    api = freeswitch.API()
    method = env:getHeader("Request-Method")
    http_uri = env:getHeader("HTTP-Request-URI")
    http_query = env:getHeader("HTTP-QUERY")
    accept = env:getHeader("Accept")
    uuid = string.sub(http_uri, "11") -- remove /channels/ from uri
    freeswitch.consoleLog("ERR", "[" .. method .. "]\n")
    -- freeswitch.consoleLog("ERR", http_uri .. "\n")
    -- freeswitch.consoleLog("ERR", http_query .. "\n")

    if (method == "GET") then
        if not (uuid == "") then
            format = ""
            if accept == "application/json" then
                format = " json"
            end
            ret = api:execute("uuid_dump", uuid .. format)
        else
            format = ""
            if (accept == "application/json") then
                format = " as json"
            end
            ret = api:execute("show", "channels" .. format)
        end
    elseif (method == "POST") then
        dest = env:getHeader("destNumber")
        app = "echo"
        dialstr = "user/" .. dest .. " &" .. app
        print(dialstr)
        ret = api:execute("originate", dialstr)
    elseif method == "PUT" then
        if action == "nomedia" then
            cmd = "uuid_media"
            arg = uuid .. " off"
        elseif action == "media" then
            cmd = "uuid_media"
            arg = uuid .. " on"
        elseif action == "hold" then
            cmd = "uuid_hold"
            arg = "on " .. uuid
        elseif action == "media" then
            cmd = "uuid_media"
            arg = "off" .. uuid
        end
        ret = api:execute(cmd, arg)
    elseif method == "DELETE" then
        if not (uuid == "") then
            cmd = "uuid_kill"
            arg = uuid
        else
            cmd = "hupall"
            arg = ""
        end
        ret = api:execute(cmd, arg)
    end
    headers()
    stream:write(ret .. "\n")

使用Curl测试RESTfulAPI的例子如下:

curl -0 localhost:8081/channels
curl -0 -XPOST -d "destNumber=1000" localhost:8081/channels
curl -0 localhost:8081/channels/1f0802b7-3568-4eb6-b372-182861b56d9b
curl -0 -H "Accept: application/json" localhost:8081/channels/1f0802b7-3568-4eb6-b372-182861b56d9b
curl -0 -XDELETE localhost:8081/channels

关于本模块更详细的信息,请参阅:https://confluence.freeswitch.org/display/FREESWITCH`mod_verto`



本书版权所有 © 杜金房及各位贡献者 2016-2023,仅供在线阅读,谢绝一切形式转载。 本书还在写作中,持续更新。 如果你也想写上几句,欢迎加入我们。 | 返回首页 |