基于华为云语音通知 VoiceCall 的应用上线记录并分享.NET CORE DEMO

 

最近公司要上线语音通知功能,需求如下:

场景:发生报警时,自动通知到指定的手机号,同时,提供几个按键选项,例如,语音通知如下:

   

   “您好,XXX小区发生XXXX报警,按1确认报警,按2忽略报警,按3屏蔽报警,暂不处理请挂机”

->用户按1,播放:您的确认请求已提交,处理结果稍候将以短信形式通知您 ->通过呼叫状态API识别按键1 ->执行操作A

->用户按2,播放:您的忽略请求已提交,处理结果稍候将以短信形式通知您 ->通过呼叫状态API识别按键2 ->执行操作B

->用户按3,播放:您的屏蔽请求已提交,处理结果稍候将以短信形式通知您 ->通过呼叫状态API识别按键3 ->执行操作C

其实主要就是要识别用户的按键,有的供应商叫 DTMF,有的叫交互式语音通知,有的叫IvrCall,就这个功能点,调查了大大小小几家供应商,要么嫌弃我们发送量太少,要么不提供报警类的语音通知,要么对接的技术人员不专业,最后还是,选择了华为云,理由如下:

  1. 相信华为多年来在通信领域的能力,在语音/短信等方面应该是有优势的;

  2. 华为云语音通知可提供96开头的号码,让我们的业务更正规;

  3. 华为云语音通知VoiceCall对接的技术人员是最专业的;

在官网提交了申请之后,一个工作日内,工作人员就联系了我,确认了相关需求可实现,同时详细介绍了开发流程和费用等问题,之后半小时之内就收到了测试环境邮件。

根据我们的需求,主要使用了 :

大客户简单授权API:https://support.huaweicloud.com/api-VoiceCall/rtc_05_0002.html

语音通知API:https://support.huaweicloud.com/api-VoiceCall/rtc_05_0013.html

呼叫状态和话单API:https://support.huaweicloud.com/api-VoiceCall/rtc_05_0014.html

其中在处理呼叫状态和话单API时,遇到了些问题,没想到华为云技术支持人员在晚上9点多依然回复了邮件,要知道,这只是调试阶段,能这么及时的相应,也是要点赞的。

经过两天的调试,我们基本上已经完成了开发,准备提交商用了,稍稍总结下,到目前为止,选择华为云VoiceCall是正确的选择。

最后,因为我们是.NET CORE环境开发,华为云官网并未提供DEMO,因此我会把我们的代码整理下,发出来供.NET 的客户参考。

 

发送测试语音:

        /// <summary>
        /// 发送测试语音短信,test_template01_kuaidi,您有$[NUM_2]件快递请到$[TXT_32]领取
        /// </summary>
        /// <param name="PhoneNum">逗号分隔的电话号码</param>
        /// <returns></returns>
        [HttpPost]
        [ActionName("SendVoiceCall")]
        public OperatedResult<List<SendVoiceCallResult>> SendNormalVoiceCall(string PhoneNum)
        {
            try
            {
                List<SendVoiceCallResult> listResult = new List<SendVoiceCallResult>();
                int successCount = 0;

                string numstr = PhoneNum;
                List<string> ListPhones = new List<string>();
                var nums = numstr.Split(',').ToList();
                nums.ForEach(x =>
                {
                    //固定电话 以 区号开头的 例如:+8602165522102,需要改为 +862165522102
                    if (x.StartsWith("+860"))
                    {
                        x = "+86" + x.Remove(0, 4);
                    }
                    //固定电话 以区号开头,去掉0
                    if (x.StartsWith("0"))
                    {
                        x = "+86" + x.Remove(0, 1);
                    }
                    //11位手机号
                    if (x.Length == 11 && x.StartsWith("1"))
                    {
                        x = "+86" + x;
                    }
                    ListPhones.Add(x);
                });

                ListPhones.ForEach(x =>
                {                

                    string Url = $"{_appSettings.Value.BaseUrl}:{_appSettings.Value.Port}{_appSettings.Value.SendVoiceCallUrl}?app_key={_appSettings.Value.AppKey}&access_token={SpTokenHelper.HuaWeiSpTokenInfo.AccessToken}&format=json";
                    Dictionary<string, string> header = new Dictionary<string, string>();
                    header.Add("ContentType", "application/json; charset=UTF-8");
                    VoiceCallRequestBody body = new VoiceCallRequestBody();
                    body.bindNbr = _appSettings.Value.BindNbr;
                    body.displayNbr = _appSettings.Value.DisplayNbr;
                    body.calleeNbr = x;
                    //您有$[3]件快递请到$[人民公园]领取,按9重听。
                    body.playInfoList = new PlayContentInfo[] { new PlayContentInfo() { templateParas = new string[] {"3","人民公园" }, templateId = "test_template01_kuaidi", collectInd = 1, collectContentTriggerReplaying = "9", replayAfterCollection = "true" } };
                    body.returnIdlePort = "true";
                    body.userData =Guid.NewGuid().ToString();                    
                    body.statusUrl = _appSettings.Value.StatusUrl.ToBase64Str();                   
                    body.feeUrl = _appSettings.Value.FeeUrl.ToBase64Str();
                    var response = HttpHelper.HttpPostAsync(Url, JsonConvert.SerializeObject(body), header, null, "application/json").Result;

                    SendVoiceCallResponse re = JsonConvert.DeserializeObject<SendVoiceCallResponse>(response);
                    _logger.LogInformation($"PhoneNum:{x},,ResultCode:{re.resultcode},ResultDesc{re.resultdesc},SessionID:{re.sessionid},IdlePort:{re.idleport}");
                    listResult.Add(new SendVoiceCallResult() { Phone = x, Response = re, AlarmContent = JsonConvert.SerializeObject(body) });
                    if (re.resultcode == "0")
                    {
                        successCount++;                      
                    }                   

                });


                return OperatedResult<List<SendVoiceCallResult>>.Success($"共{ListPhones.Count}条呼叫,发送成功{successCount}条", listResult);
            }
            catch (Exception ex)
            {

                _logger.LogError("SendNormalVoiceCall失败:" + ex.Message);
                return OperatedResult<List<SendVoiceCallResult>>.Fail($"发起语音呼叫失败");
            }          

        }

 

 

 

回调函数:

        /// <summary>
        /// 华为云VoiceCall呼叫状态回复
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost]
        [ActionName("StatusCallBack")]
        public IActionResult StatusCallBack(StatusRequestCallBackInfo request)
        {
            _logger.LogDebug(JsonConvert.SerializeObject(request));
            
            return  Ok(new StatusResponse() {resultdesc="",resultcode="0" });
        }

 

 

 大客户认证:

        /// <summary>
        /// 从华为云获取Token
        /// </summary>
        /// <returns></returns>
        public  OperatedResult<HuaWeiSpTokenInfo>  GetSpToken()
        {
            string Url = $"{_appSettings.Value.BaseUrl}:{_appSettings.Value.Port}{_appSettings.Value.GetTokenUrl}?app_key={_appSettings.Value.AppKey}&username={_appSettings.Value.UserName}&format=json";

            Dictionary<string, string> header = new Dictionary<string, string>();
            header.Add("ContentType", "application/x-www-form-urlencoded; charset=UTF-8");
            header.Add("Accept", "*/*");
           // header.Add("Authorization", _appSettings.Value.UserPsw);

            var response = HttpHelper.HttpPostAsync(Url, null, header,_appSettings.Value.UserPsw).Result;

            SpGetTokenResponse re = JsonConvert.DeserializeObject<SpGetTokenResponse>(response);
            if (re.resultcode == "0")
            {
                //获取成功
                HuaWeiSpTokenInfo.AccessToken = re.access_token;
                HuaWeiSpTokenInfo.RefreshToken = re.refresh_token;
                HuaWeiSpTokenInfo.ExpiresIn = re.expires_in;

                HuaWeiSpTokenInfo.TokenStartTime = DateTime.Now;
                HuaWeiSpTokenInfo.TokenEndTime = DateTime.Now.AddSeconds( Convert.ToInt32( re.expires_in));

                return OperatedResult<HuaWeiSpTokenInfo>.Success(HuaWeiSpTokenInfo);
            }
            else
            {
                SpGetTokenResponseCode code = new SpGetTokenResponseCode();
                code.list.Where(x => x.Code == re.resultcode).FirstOrDefault();

                return OperatedResult<HuaWeiSpTokenInfo>.Fail($"执行失败:ResultCode:{re.resultcode},ResultDesc:{re.resultdesc}");
            }
        }

 

刷新Token:

        /// <summary>
        /// 从华为云刷新Token
        /// </summary>
        /// <returns></returns>
        public OperatedResult<HuaWeiSpTokenInfo> RefreshSpToken()
        {
            string Url = $"{_appSettings.Value.BaseUrl}:{_appSettings.Value.Port}{_appSettings.Value.RefreshTokenUrl}";

            Dictionary<string, string> header = new Dictionary<string, string>();
            //header.Add("ContentType", "application/x-www-form-urlencoded; charset=UTF-8");
            header.Add("Accept", "*/*");           

            string PostData = $"grant_type=refresh_token&refresh_token={HuaWeiSpTokenInfo.RefreshToken}&app_key={_appSettings.Value.AppKey}&app_secret={_appSettings.Value.AppSecret}";

            var response = HttpHelper.HttpPostAsync(Url, PostData, header,null, "application/x-www-form-urlencoded").Result;

            SpRefreshTokenResponse re = JsonConvert.DeserializeObject<SpRefreshTokenResponse>(response);
            if (re.resultcode == "0")
            {
                //获取成功
                HuaWeiSpTokenInfo.AccessToken = re.access_token;
                HuaWeiSpTokenInfo.RefreshToken = re.refresh_token;
                HuaWeiSpTokenInfo.ExpiresIn = re.expires_in;

                HuaWeiSpTokenInfo.TokenStartTime = DateTime.Now;
                HuaWeiSpTokenInfo.TokenEndTime = DateTime.Now.AddSeconds(Convert.ToInt32(re.expires_in));

                return OperatedResult<HuaWeiSpTokenInfo>.Success(HuaWeiSpTokenInfo);
            }
            else
            {
                //获取失败
                SpRefreshTokenResponseCode code = new SpRefreshTokenResponseCode();
                code.list.Where(x => x.Code == re.resultcode).FirstOrDefault();

                return OperatedResult<HuaWeiSpTokenInfo>.Fail($"执行失败:ResultCode:{re.resultcode},ResultDesc:{re.resultdesc}");
            }
        }

注销Token:

        /// <summary>
        /// 从华为云注销Token
        /// </summary>
        /// <returns></returns>
        public OperatedResult<bool> CancleSpToken()
        {
            string Url = $"{_appSettings.Value.BaseUrl}:{_appSettings.Value.Port}{_appSettings.Value.CancleTokenUrl}?app_key={_appSettings.Value.AppKey}&access_token={HuaWeiSpTokenInfo.AccessToken}";

            Dictionary<string, string> header = new Dictionary<string, string>();
            header.Add("ContentType", "application/x-www-form-urlencoded; charset=UTF-8");
            header.Add("Accept", "*/*");
           
            var response = HttpHelper.HttpPostAsync(Url, null, header).Result;

            SpCancleTokenResponse re = JsonConvert.DeserializeObject<SpCancleTokenResponse>(response);
            if (re.resultcode == "0")
            {
                //获取成功
                HuaWeiSpTokenInfo.AccessToken = string.Empty;
                HuaWeiSpTokenInfo.RefreshToken = string.Empty;
                HuaWeiSpTokenInfo.ExpiresIn = "0";

                HuaWeiSpTokenInfo.TokenStartTime = DateTime.MinValue;
                HuaWeiSpTokenInfo.TokenEndTime = DateTime.MinValue;

                return OperatedResult<bool>.Success();
            }
            else
            {
                //失败
                SpCancleTokenResponseCode code = new SpCancleTokenResponseCode();
                code.list.Where(x => x.Code == re.resultcode).FirstOrDefault();

                return OperatedResult<bool>.Fail($"执行失败:ResultCode:{re.resultcode},ResultDesc:{re.resultdesc}");
            }
        }

 

 Post请求:

        /// <summary>
        /// 异步POST请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="postData"></param>
        /// <param name="headers"></param>
        /// <param name="contentType"></param>
        /// <param name="customToken"></param>
        /// <param name="timeout">请求响应超时时间,单位/s(默认100秒)</param>
        /// <param name="encoding">默认UTF8</param>
        /// <returns></returns>
        public static async Task<string> HttpPostAsync(string url, string postData, Dictionary<string, string> headers = null,string customToken=null, string contentType = null, int timeout = 0, Encoding encoding = null)
            {
                using (HttpClient client = new HttpClient(new HttpClientHandler() { ServerCertificateCustomValidationCallback = (a, b, c, d) => true }))
                {
                    if (headers != null)
                    {
                        foreach (KeyValuePair<string, string> header in headers)
                        {
                            client.DefaultRequestHeaders.Add(header.Key, header.Value);
                           
                        }
                    }
                    if(customToken!=null)
                {
                    client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", customToken);
                }

                   
                    if (timeout > 0)
                    {
                        client.Timeout = new TimeSpan(0, 0, timeout);
                    }
              
                using (HttpContent content = new StringContent(postData ?? "", encoding ?? Encoding.UTF8))
                {
                    if (contentType != null)
                    {
                        content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
                    }
                    using (HttpResponseMessage responseMessage = await client.PostAsync(url, content))
                    {
                        Byte[] resultBytes = await responseMessage.Content.ReadAsByteArrayAsync();
                        return Encoding.UTF8.GetString(resultBytes);
                    }
                }
                }
            }
        }

 

 

 

 

 

posted @ 2018-10-13 13:47  shuzhen.yu  阅读(1462)  评论(0编辑  收藏  举报