UDN 企业互联网技术社区 U视野 语音服务器的选型

语音服务器的选型

audio audio 2017-1-11 10:24
分享到:
摘要:   最近游戏要接入一下语音服务器,调查了一下融合的语音sdk   腾讯云GVoice:https://www.qcloud.com/document/product/556/7673   好像只有这个比较靠谱,但是收费好像有点贵,还是决定基于原有的免费的百度语 ...
  前言

  最近游戏要接入一下语音服务器,调查了一下融合的语音sdk

  腾讯云GVoice:https://www.qcloud.com/document/product/556/7673

  好像只有这个比较靠谱,但是收费好像有点贵,还是决定基于原有的免费的百度语音识别造一个轮子

  选型

  要解决几个问题

  • 语音转文字翻译


  • 高效的web服务器


  • 分布式的文件存储


  • 与游戏服务器沟通的消息队列选择


  语音转文字翻译

  这个真没法自己造轮子,选择了百度的语音服务

  语音识别50000次/日配额

  支持的语音时长上限为60s

  • auth档


  http://developer.baidu.com/wiki/index.php?title=docs/oauth/client

  • 刷新access_token


  http://developer.baidu.com/wiki/ ... 5%8F%96Access_Token

  • 语音识别接口


  http://yuyin.baidu.com/docs/asr/57


local new_timer = ngx.timer.at

local access_token
local refresh_token

function M.timer_refresh_token(resp)
    local expires_in_sec = resp.expires_in - 3600
    expires_in_sec = expires_in_sec < 0 and 1 or expires_in_sec
    --过期前一天刷新token
    new_timer(expires_in_sec,M.refresh_token)
end

function M.gen_token()
    if not access_token then
        local data = { grant_type="client_credentials", client_id = Config.AppKey, client_secret = Config.AppSecret}
        local resp,err = http_util.get_baidu_token(Config.TOKEN_URL, data)
        access_token = resp.access_token
        refresh_token = resp.refresh_token
        M.timer_refresh_token(resp)
    end
end

function M.refresh_token()
    if refresh_token then
        local data = { grant_type="refresh_token", client_id = Config.AppKey, client_secret = Config.AppSecret, refresh_token = refresh_token }
        local resp,err = http_util.get_baidu_token(Config.TOKEN_URL, data)
        access_token = resp.access_token
        refresh_token = resp.refresh_token
        M.timer_refresh_token(resp)
    else
        M.gen_token()
    end
end


function M.translate_voice(voice)
    local len = string.len(voice)
    local base64_str =  ngx.encode_base64(voice)
    local data = {cuid = Config.CUID, token= access_token, channel = 1, format = "amr", rate = 8000,
            len = len, speech = base64_str }
    local resp,err = http_util.post_ret_json(Config.VOICE_URL, data)
    if not err then
        local err_no = resp.errno
        if ERR_TBL[err_no] then
            return ERR_TBL[err_no]
        end
        return resp.result[1]
    end
    return err
end
   
  web服务器

  所有的结构是在python在Flask上构建的,怕运行效率不行想重新写一个.几经比较之后,没有选择比较熟悉的java语言和tornado,而是选择了openresty,主要是基于几点考虑

  是否是经过验证的框架

  是否是熟悉的开发语言

  开发和部署是否简便快捷

  openresty 是在nginx的基础上嵌入了lua的支持,兼备了Python快速开发和Nginx C模块的高性能

  文件存储

  前期小规模的文件存储直接单机就可以了.而且语音这种是有时效性的,通过ttl过期即可清除,磁盘空间不会无限增长.

  但为了做个新的尝试,也调查了一下分布式的小文件存储



  tfs淘宝的开源方案年久失修,果断弃之



  要加入mysql弃之



  c编写,用的人比较多,但是看了几篇对比文章之后也没有做为最终的选择





  借鉴了seaweedfs和fastdfs,这篇文章可以对bfs有个大概的了解,没有用这个的原因是加加入



  c++编写,不熟悉

  最终使用了seaweedfs go语言编写,简单易用

  参考:

  http://blog.qiniu.com/archives/2546

  http://wenjun.org/?p=1087

  http://www.simlinux.com/books/FastDFS.pdf

  消息队列

  游戏内auth和后台gm通信中间件使用的rabbitmq,为了保持一致性也使用了这个

  架构

  
audio_server.png

  
  流程

  由玩家发起语音聊天,将语音压缩成amr上传到中心主机nginx上,由nginx反代seaweedfs集群完成语音文件的存储,然后将返回的文件id加上内网的集群ip组合成语音id将消息信息push到rabbitmq队列中,游戏服务器作为mq的订阅者实时处理队列内容将消息按频道和语音id广播给对应的游戏客户端,游戏客户端用语音id请求中心主机nginx再从代理的seaweedfs集群中取语音文件.整个语音聊天的过程就完成了.

  关于百度语音识别部分

  百度语音识别API并不支持流式上传数据,而且把识别这部分放到上传语音的过程中加重了rpc调用的负担.所以这部分可以放到游戏客户端直接请求百度api

来源:audio

相关阅读

分享到:

最新评论

一周焦点

    关注我们:
    关于我们
    联系我们
    • 电话:4006-815-456
    • 邮件:udn@yonyou.com
    • 地址:北京市海淀区北清路68号
    移动客户端下载
    关注我们
    • 微信公众号:yonyouudn
    • 扫描右侧二维码关注我们
    • 专注企业互联网的技术社区
    版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
    返回顶部