更新时间:2024-09-24 GMT+08:00
C#
样例 |
|
---|---|
环境要求 |
.NET Core 2.0及以上版本或.NET Framework 4.7.1及以上版本。 |
引用库 |
Newtonsoft.Json 11.0.2,请参考https://www.newtonsoft.com/json获取。 |
- 本文档所述Demo在提供服务的过程中,可能会涉及个人数据的使用,建议您遵从国家的相关法律采取足够的措施,以确保用户的个人数据受到充分的保护。
- 本文档所述Demo仅用于功能演示,不允许客户直接进行商业使用。
- 本文档信息仅供参考,不构成任何要约或承诺。
“语音回呼场景API”代码样例
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text; namespace voicecall_csharp_demo_x_aksk_ { class VoiceCall { string base_url = "https://{domain}:{port}"; //APP接入地址,购买服务时下发,请替换为实际值 string appKey = "***appKey***"; //语音回呼应用的appKey,购买服务时下发,请替换为实际值 string appSecret = "***appSecret***"; //语音回呼应用的appSecret,购买服务时下发,请替换为实际值 static void Main(string[] args) { //主叫号码,被叫号码请替换为实际号码.固话号码从控制台号码管理页获取 voiceCallAPI("+86531*******4", "+86135*******1", "+86531*******4", "+86135*******2"); } static void voiceCallAPI(string displayNbr, string callerNbr, string displayCalleeNbr, string calleeNbr) { if (String.IsNullOrEmpty(displayNbr) || String.IsNullOrEmpty(callerNbr) || String.IsNullOrEmpty(displayCalleeNbr) || String.IsNullOrEmpty(calleeNbr)) { return; } string apiURI = "/rest/httpsessions/click2Call/v2.0"; //接口URI string requestUrl = base_url + apiURI; try { //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 //.NET Framework 4.7.1及以上版本,请采用如下代码 var sslHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, err) => { return true; } }; HttpClient client = new HttpClient(sslHandler, true); //低于.NET Framework 4.7.1版本,请采用如下代码 //HttpClient client = new HttpClient(); //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); //请求Headers client.DefaultRequestHeaders.Add("Authorization", "AKSK realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""); client.DefaultRequestHeaders.Add("X-AKSK", buildAKSKHeader(appKey, appSecret)); //请求Body var body = new Dictionary<string, object>() { /*必填参数*/ {"displayNbr", displayNbr},//主叫用户手机终端的来电显示号码。 {"callerNbr", callerNbr},//发起呼叫时所使用的主叫号码。 {"displayCalleeNbr", displayCalleeNbr},//被叫用户终端的来电显示号码。 {"calleeNbr", calleeNbr}//发起呼叫时所拨打的被叫号码。 /*选填参数*/ //{"maxDuration", 0}, //允许单次通话进行的最长时间 //{"lastMinVoice", "lastmin_voice1.wav"}, //最后一分钟放音提示音 //{"lastMinToUE", "both"}, //最后一分钟放音的播放对象 //{"playPreVoice", "false"}, //设置主叫(callerNbr)应答语音回呼后,呼叫被叫(calleeNbr)前,是否向主叫(callerNbr)播放提示音 //{"preVoice", "pre_voice1.wav"}, //设置主叫(callerNbr)应答语音回呼后,呼叫被叫(calleeNbr)前向主叫播放的提示音 //{"waitVoice", "wait_voice1.wav"}, //设置主叫应答语音回呼后的等待音 //{"calleeMedia", "all"}, //指定被叫的媒体音播放方式 //{"statusUrl", ""}, //设置SP接收状态上报的URL,要求使用BASE64编码 //{"feeUrl", ""}, //设置SP接收话单上报的URL,要求使用BASE64编码 //{"recordFlag", "false"}, //设置语音回呼通话过程是否录音 //{"recordHintTone", "recordhint_voice1.wav"}, //设置使用录音功能的提示音 //{"partyTypeRequiredInDisconnect", "false"}, //disconnect状态是否需要携带通话主动挂机的用户类型 //{"returnIdlePort", "false"}, //指示是否需要返回平台空闲呼叫端口数量 //{"userData", "customerId123"} //设置用户的附属信息 }; HttpContent content = new StringContent(JsonConvert.SerializeObject(body)); //请求Headers中的Content-Type参数 content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = client.PostAsync(requestUrl, content).Result; Console.WriteLine(response.StatusCode); var res = response.Content.ReadAsStringAsync().Result; Console.WriteLine(res); //打印响应结果 } catch (Exception e) { Console.WriteLine(e.StackTrace); Console.WriteLine(e.Message); //打印错误信息 } } static string buildAKSKHeader(string appKey, string appSecret) { string now = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); //Created string nonce = Guid.NewGuid().ToString().Replace("-", ""); //Nonce String str = nonce + now; byte[] keyByte = Encoding.UTF8.GetBytes(appSecret); byte[] messageBytes = Encoding.UTF8.GetBytes(str); using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); string base64 = Convert.ToBase64String(hashmessage); return String.Format("UsernameToken Username=\"{0}\",PasswordDigest=\"{1}\",Nonce=\"{2}\",Created=\"{3}\"", appKey, base64, nonce, now); } } //低于.NET Framework 4.7.1版本,启用如下方法 //static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) //{ // return true; //} } }
“获取录音文件下载地址API”代码样例
using System; using System.Collections.Specialized; using System.IO; using System.Net; using System.Net.Http; using System.Security.Cryptography; using System.Text; namespace voicecall_csharp_demo_x_aksk_ { class GetRecordLink { string base_url = "https://{domain}:{port}"; //APP接入地址,购买服务时下发,请替换为实际值 static void Main(string[] args) { //语音回呼应用的appKey和appSecret,购买服务时下发,请替换为实际值 string aksk = buildAKSKHeader("***appKey***", "***appSecret***"); //录音文件名和录音存储服务器域名,从话单通知中获取 string location = getRecordLinkAPI("1200_366_0_20161228102743.wav", "ostor.huawei.com", aksk); //打印录音文件下载地址 Console.WriteLine($"The record file download link is: {location}"); } static string getRecordLinkAPI(string fileName, string recordDomain, string xaksk) { if (String.IsNullOrEmpty(fileName) || String.IsNullOrEmpty(recordDomain) || String.IsNullOrEmpty(xaksk)) { return; } var location; string apiURI = "/rest/provision/voice/record/v1.0"; //接口URI var keyValues = new NameValueCollection(); keyValues.Add("fileName", fileName); keyValues.Add("recordDomain", recordDomain); string requestUrl = base_url + apiURI + "?" + buildQueryString(keyValues); try { //为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题 //.NET Framework 4.7.1及以上版本,请采用如下代码 var sslHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, err) => { return true; } }; sslHandler.AllowAutoRedirect = false; //关闭重定向 HttpClient client = new HttpClient(sslHandler, true); //低于.NET Framework 4.7.1版本,请采用如下代码 //var sslHandler = new HttpClientHandler(); //sslHandler.AllowAutoRedirect = false; //HttpClient client = new HttpClient(sslHandler); //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); //请求Headers client.DefaultRequestHeaders.Add("Authorization", "AKSK realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""); client.DefaultRequestHeaders.Add("X-AKSK", xaksk); var response = client.GetAsync(requestUrl).Result; //GET请求 if (response.StatusCode.Equals(301)) { location = Convert.ToString(response.Headers.GetValues("Location")); } else { var res = response.Content.ReadAsStringAsync().Result; Console.WriteLine(response.StatusCode); Console.WriteLine(res); //打印响应结果 } } catch (Exception e) { Console.WriteLine(e.StackTrace); Console.WriteLine(e.Message); //打印错误信息 } return location; } static string buildAKSKHeader(string appKey, string appSecret) { string now = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); //Created string nonce = Guid.NewGuid().ToString().Replace("-", ""); //Nonce String str = nonce + now; byte[] keyByte = Encoding.UTF8.GetBytes(appSecret); byte[] messageBytes = Encoding.UTF8.GetBytes(str); using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); string base64 = Convert.ToBase64String(hashmessage); return String.Format("UsernameToken Username=\"{0}\",PasswordDigest=\"{1}\",Nonce=\"{2}\",Created=\"{3}\"", appKey, base64, nonce, now); } } static string buildQueryString(NameValueCollection keyValues) { StringBuilder temp = new StringBuilder(); foreach (string item in keyValues.Keys) { temp.Append(item).Append("=").Append(WebUtility.UrlEncode(keyValues.Get(item))).Append("&"); } return temp.Remove(temp.Length - 1, 1).ToString(); } //低于.NET Framework 4.7.1版本,启用如下方法 //static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) //{ // return true; //} } }
“呼叫状态通知API”代码样例
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; namespace voicecall_csharp_demo_x_aksk_ { class CallEventImpl { static void Main(string[] args) { //呼叫事件通知样例 string jsonBody = JsonConvert.SerializeObject(new Dictionary<string, object>(){ {"eventType", "callout"}, {"statusInfo", new Dictionary<string, object>(){ {"sessionId", "1201_612_4294967295_20190124030424@callenabler245.huaweicaas.com"}, {"timestamp", "2019-01-24 03:04:24"}, {"caller", "+86138*******2"}, {"called", "+86138*******1"}, } } }); Console.WriteLine("jsonBody:" + jsonBody); OnCallEvent(jsonBody); //呼叫事件处理 } /// <summary> /// 呼叫事件通知,详细内容以接口文档为准 /// </summary> /// <param name="jsonBody"></param> static void OnCallEvent(string jsonBody) { JObject jsonObj = (JObject)JsonConvert.DeserializeObject(jsonBody); //将通知消息解析为jsonObj string eventType = jsonObj["eventType"].ToString(); //通知事件类型 if ("fee".Equals(eventType)) { Console.WriteLine("EventType error:" + eventType); return; } if (!jsonObj.ContainsKey("statusInfo")) { Console.WriteLine("param error: no statusInfo."); return; } JObject statusInfo = (JObject)jsonObj["statusInfo"]; //呼叫状态事件信息 Console.WriteLine("eventType:" + eventType); //打印通知事件类型 //callout:呼出事件 if ("callout".Equals(eventType)) { /** * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理 * * 'timestamp': 该呼叫事件发生时语音通话平台的UNIX时间戳 * 'userData': 用户附属信息 * 'sessionId': 通话链路的标识ID * 'caller': 主叫号码 * 'called': 被叫号码 */ if (statusInfo.ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + statusInfo["sessionId"]); } return; } //alerting:振铃事件 if ("alerting".Equals(eventType)) { /** * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理 * * 'timestamp': 该呼叫事件发生时语音通话平台的UNIX时间戳 * 'userData': 用户附属信息 * 'sessionId': 通话链路的标识ID * 'caller': 主叫号码 * 'called': 被叫号码 */ if (statusInfo.ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + statusInfo["sessionId"]); } return; } //answer:应答事件 if ("answer".Equals(eventType)) { /** * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理 * * 'timestamp': 该呼叫事件发生时语音通话平台的UNIX时间戳 * 'userData': 用户附属信息 * 'sessionId': 通话链路的标识ID * 'caller': 主叫号码 * 'called': 被叫号码 */ if (statusInfo.ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + statusInfo["sessionId"]); } return; } //collectInfo:放音收号结果事件,仅应用于语音通知场景 if ("collectInfo".Equals(eventType)) { /** * Example: 此处以解析digitInfo为例,请按需解析所需参数并自行实现相关处理 * * 'timestamp': 该呼叫事件发生时语音通话平台的UNIX时间戳 * 'sessionId': 通话链路的标识ID * 'digitInfo': 放音收号场景中,语音通话平台对开发者进行放音收号操作的结果描述 */ if (statusInfo.ContainsKey("digitInfo")) { Console.WriteLine("digitInfo:" + statusInfo["digitInfo"]); } return; } //disconnect:挂机事件 if ("disconnect".Equals(eventType)) { /** * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理 * * 'timestamp': 该呼叫事件发生时语音通话平台的UNIX时间戳 * 'userData': 用户附属信息 * 'sessionId': 通话链路的标识ID * 'caller': 主叫号码 * 'called': 被叫号码 * 'partyType': 挂机的用户类型,仅在语音回呼场景携带 * 'stateCode': 通话挂机的原因值 * 'stateDesc': 通话挂机的原因值的描述 */ if (statusInfo.ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + statusInfo["sessionId"]); } return; } } } }
“话单通知API”代码样例
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; namespace voicecall_csharp_demo_x_aksk_ { class FeeImpl { static void Main(string[] args) { //话单通知样例 string jsonBody = JsonConvert.SerializeObject(new Dictionary<string, object>(){ {"eventType", "fee"}, {"feeLst", new object[] { new Dictionary<string, object>(){ {"direction", 0}, //通话的呼叫方向,以语音通话平台为基准 {"spId", "CaaS_Test_01"}, //客户的云服务账号 {"appKey", "ka4k*****Em2"}, //应用的app_key,购买服务时下发,请替换为实际值 {"icid", "CAE-20190124110424-12019775"}, //呼叫记录的唯一标识 {"bindNum", "+8675512****78"}, //发起此次呼叫的CallEnabler业务号码,即绑定号码 {"sessionId", "1201_612_4294967295_20190124030424@callenabler245.huaweicaas.com"}, //通话链路的唯一标识 {"callerNum", "+86138****0022"}, //主叫号码 {"calleeNum", "+86138****0021"}, //被叫号码 {"fwdDisplayNum", "+86138****0022"}, //转接呼叫时的显示号码(仅语音回呼场景携带) {"fwdDstNum", "+86138****7021"}, //转接呼叫时的转接号码(仅语音回呼场景携带) {"fwdStartTime", "2019-01-24 03:04:31"}, //转接呼叫操作的开始时间(仅语音回呼场景携带) {"fwdAlertingTime", "2019-01-24 03:04:36"}, //转接呼叫操作后的振铃时间(仅语音回呼场景携带) {"fwdAnswerTime", "2019-01-24 03:04:38"}, //转接呼叫操作后的应答时间(仅语音回呼场景携带) {"callEndTime", "2019-01-24 03:04:49"}, //呼叫结束时间 {"fwdUnaswRsn", 0}, //转接呼叫操作失败的Q850原因值 {"failTime", ""}, //呼入,呼出的失败时间 {"ulFailReason", 0}, //通话失败的拆线点 {"sipStatusCode", 0}, //呼入,呼出的失败SIP状态码 {"callOutStartTime", "2019-01-24 03:04:24"}, //Initcall的呼出开始时间 {"callOutAlertingTime", "2019-01-24 03:04:27"}, //Initcall的呼出振铃时间 {"callOutAnswerTime", "2019-01-24 03:04:31"}, //Initcall的呼出应答时间 {"callOutUnaswRsn", 0}, //Initcall的呼出失败的Q850原因值 {"dynIVRStartTime", ""}, //自定义动态IVR开始时间(仅语音通知场景携带) {"dynIVRPath", ""}, //自定义动态IVR按键路径(仅语音通知场景携带) {"recordFlag", 0}, //录音标识 {"recordStartTime", ""}, //录音开始时间(仅语音回呼场景携带) {"recordObjectName", ""}, //录音文件名(仅语音回呼场景携带) {"recordBucketName", ""}, //录音文件所在的目录名(仅语音回呼场景携带) {"recordDomain", ""}, //存放录音文件的域名(仅语音回呼场景携带) {"recordFileDownloadUrl", ""}, //录音文件下载地址(仅语音回呼场景携带) {"ttsPlayTimes", 0}, //应用TTS功能时,使用TTS的总次数 {"ttsTransDuration", 0}, //应用TTS功能时,TTS Server进行TTS转换的总时长(单位为秒) {"serviceType", "002"}, //携带呼叫的业务类型信息 {"hostName", "callenabler245.huaweicaas.com"}, //话单生成的服务器设备对应的主机名 {"userData", "customerId123"} //用户附属信息 } } } }); Console.WriteLine(jsonBody); OnFeeEvent(jsonBody); //话单处理 } /// <summary> /// 话单通知,详细内容以接口文档为准 /// </summary> /// <param name="jsonBody"></param> static void OnFeeEvent(string jsonBody) { JObject jsonObj = (JObject)JsonConvert.DeserializeObject(jsonBody); //将通知消息解析为jsonObj string eventType = jsonObj["eventType"].ToString(); //通知事件类型 if (!"fee".Equals(eventType)) { Console.WriteLine("EventType error:" + eventType); return; } if (!jsonObj.ContainsKey("feeLst")) { Console.WriteLine("param error: no feeLst."); return; } JObject[] feeLst = jsonObj["feeLst"].ToObject<JObject[]>(); //呼叫话单事件信息 //Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理 //短时间内有多个通话结束时语音通话平台会将话单合并推送,每条消息最多携带50个话单 if (feeLst.Length > 1) { foreach (JObject loop in feeLst) { if (loop.ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + loop["sessionId"]); } } } else if (feeLst.Length == 1) { if (feeLst[0].ContainsKey("sessionId")) { Console.WriteLine("sessionId:" + feeLst[0]["sessionId"]); } } else { Console.WriteLine("feeLst error: no element."); } } } }
父主题: 语音回呼代码样例