PHP对接华为云语音通知api

<?php

namespace app\services\message;

use app\services\charge\ChargeOrderLogServices;
use think\exception\ValidateException;

class VoiceCallServices
{
    protected $callNotifyAppId;
    protected $callNotifySecret;
    protected $displayNbr;
    protected $baseUrl;
    protected $statusUrl;
    protected $templateId;
    protected $apiUrl;

    public function __construct(){
        $this->callNotifyAppId = sys_config('voice_call_key'); // Key
        $this->callNotifySecret = sys_config('voice_call_secret'); // 秘钥
        $this->displayNbr = sys_config('display_nbr'); // 固话号码
        $this->baseUrl = sys_config('voice_request_url'); // app接入地址
        $this->statusUrl = sys_config('voice_status_url'); // 呼叫状态接收地址
        $this->templateId = sys_config('voice_template_id'); // 语音模板ID
        $this->apiUrl = '/rest/httpsessions/callnotify/v2.0'; // 访问url
    }

    /**
     * 语音通知api
     * @param string $calleeNbr 被叫号码
     * @param array $data       相关参数
     */
    public function voiceNotifyAPI(string $calleeNbr,array $data){
        if(empty($this->displayNbr)) throw new ValidateException('缺少固话号码');
        if(empty($calleeNbr)) throw new ValidateException('缺少被叫号码');
        $playInfoList = array();
        // 通知模式:0模板通知,1放音文件通知
        if(sys_config('play_content_type') == 1){
            $playInfoList[] = [
                'notifyVoice' => '',
            ];
        }else{
            // 示例:模板内容:"您有${NUM_2}件快递请到${TXT_32}领取";则templateParas为["3","人民公园正门"];API将播放文本“您有3件快递请到人民公园正门领取”
            $playInfoList[] = [
                'templateId' => $this->templateId, // 模板ID
                'templateParas' => [$data['content']], // 自定义模板内容
            ];
        }
        if(empty($playInfoList)) throw new ValidateException('缺少播放信息');
        $xaksk = $this->buildAKSKHeader($this->callNotifyAppId,$this->callNotifySecret);
        $content = json_encode([
            /* 必填参数 */
            'displayNbr' => $this->displayNbr, // 固话号码,固话格式:+{国家码}{区号}{固话号码},其中区号需去掉首位的0。示例:国家码86,区号0755,固话号码28****01,填写为+8675528****01
            'calleeNbr' => $calleeNbr, // 被叫号码
            'playInfoList' => $playInfoList, // 播放信息列表,最多5个
            /* 非必要参数 */
            'statusUrl' => base64_encode($this->statusUrl), // 回调接口:语音通话平台将业务触发过程中通话的状态信息(包括呼出、振铃、摘机和挂机信息)推送至此服务器,,此参数请采用BASE64编码进行加密
            'userData' => $data['order_id'], // 拨打时携带的参数,可用于回呼状态接收接口使用,不允许携带大括号{},不允许包含中文,如果包含中文则需要BASE64编码进行加密
        ]);
        $requestUrl =  $this->baseUrl . $this->apiUrl;
        $context_options = $this->createOptions($xaksk,$content);
        try {
            $response = json_decode(file_get_contents($requestUrl,false,stream_context_create($context_options)),true); // 发送请求
            if($response['resultcode'] != 0) throw new ValidateException($response['resultdesc']);
            // 成功返回示例:["resultcode" => "0", "sessionId" => "1201_3772_4294967295_20231116094532@callenabler245.huaweicaas.com", "resultdesc" => "Success"]
            return true;
        } catch (\Exception $e){
            throw new ValidateException($e->getMessage());
        }
    }

    /**
     * 构建AKSK请求头
     * @param string $appKey 语音通知key
     * @param string $appSecret 语音通知secret
     * @return string
     */
    public function buildAKSKHeader(string $appKey,string $appSecret){
        date_default_timezone_set("UTC");
        $created = date('Y-m-d\TH:i:s\Z');
        $nonce = uniqid();
        $base64 = base64_encode(hash_hmac('sha256',($nonce.$created),$appSecret,true));
        return sprintf("UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"", $appKey, $base64, $nonce, $created);
    }

    /**
     * createOptions
     * @param $method
     * @param $xaksk
     * @param $content
     * @return array
     */
    public function createOptions($xaksk, $content){
        $headers = [
            'Content-Type: application/json;charset=UTF-8',
            'Authorization: AKSK realm="SDP",profile="UsernameToken",type="Appkey"',
            'X-AKSK: ' . $xaksk
        ];
        return [
            'http' => [
                'method' => 'POST', // 请求方法
                'header' => $headers,
                'content' => $content,
                'max_redirects' => '0', // 关闭重定向
                'ignore_errors' => true // 获取错误码,方便调测
            ],
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false
            ]
        ];
    }

    /**
     * 呼叫状态接收api
     * 接口调用请求为POST,可以使用$request->param()获取回调的参数
     * @param $jsonBody 回调参数
     * @return bool
     */
    public function voice_notify($jsonBody){
        if(!is_array($jsonBody)){
            $jsonArr = json_decode($jsonBody,true); // 将通知消息解析为关联数组
        } else {
            $jsonArr = $jsonBody;
        }
        $eventType = $jsonArr['eventType']; // 通知事件类型
        if(strcasecmp($eventType,'fee') == 0) throw new ValidateException('EventType error:' . $eventType);
        if(!array_key_exists('statusInfo',$jsonArr)) throw new ValidateException('param error:no statusInfo');
        $statusInfo = $jsonArr['statusInfo']; // 呼叫状态事件信息
        // callout:呼出事件
        if (strcasecmp($eventType, 'callout') == 0) {
            /**
             * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理
             * 'timestamp': 该呼叫事件发生时RTC业务平台的UNIX时间戳
             * 'userData': 用户附属信息,语音通知api或语音回呼api携带的参数userData
             * 'sessionId': 通话链路的标识ID
             * 'caller': 主叫号码
             * 'called': 被叫号码
             */
            if (array_key_exists('sessionId', $statusInfo)) { // 你的业务逻辑
                $text = '【呼出事件】---通话链路的标识ID:【'.$statusInfo['sessionId'].'】,呼叫事件发生时RTC业务平台的UNIX时间戳:【'.$statusInfo['timestamp'].'】,主叫号码:【'.$statusInfo['caller'].'】,被叫号码:【'.$statusInfo['called'].'】';
                ChargeOrderLogServices::createLog('语音通知',$text,$statusInfo['userData']);
            }
            return true;
        }
        // alerting:振铃事件
        if (strcasecmp($eventType, 'alerting') == 0) {
            /**
             * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理
             * 'timestamp': 该呼叫事件发生时RTC业务平台的UNIX时间戳
             * 'userData': 用户附属信息,语音通知api或语音回呼api携带的参数userData
             * 'sessionId': 通话链路的标识ID
             * 'caller': 主叫号码
             * 'called': 被叫号码
             */
            if (array_key_exists('sessionId', $statusInfo)) { // 你的业务逻辑
                $text = '【振铃事件】---通话链路的标识ID:【'.$statusInfo['sessionId'].'】,呼叫事件发生时RTC业务平台的UNIX时间戳:【'.$statusInfo['timestamp'].'】,主叫号码:【'.$statusInfo['caller'].'】,被叫号码:【'.$statusInfo['called'].'】';
                ChargeOrderLogServices::createLog('语音通知',$text,$statusInfo['userData']);
            }
            return true;
        }
        // answer:应答事件
        if (strcasecmp($eventType, 'answer') == 0) {
            /**
             * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理
             * 'timestamp': 该呼叫事件发生时RTC业务平台的UNIX时间戳
             * 'userData': 用户附属信息,语音通知api或语音回呼api携带的参数userData
             * 'sessionId': 通话链路的标识ID
             * 'caller': 主叫号码
             * 'called': 被叫号码
             */
            if (array_key_exists('sessionId', $statusInfo)) { // 你的业务逻辑
                $text = '【应答事件】---通话链路的标识ID:【'.$statusInfo['sessionId'].'】,呼叫事件发生时RTC业务平台的UNIX时间戳:【'.$statusInfo['timestamp'].'】,主叫号码:【'.$statusInfo['caller'].'】,被叫号码:【'.$statusInfo['called'].'】';
                ChargeOrderLogServices::createLog('语音通知',$text,$statusInfo['userData']);
            }
            return true;
        }
        // collectInfo:放音收号结果事件,仅应用于语音通知场景
        if (strcasecmp($eventType, 'collectInfo') == 0) {
            /**
             * Example: 此处以解析digitInfo为例,请按需解析所需参数并自行实现相关处理
             * 'timestamp': 该呼叫事件发生时RTC业务平台的UNIX时间戳
             * 'sessionId': 通话链路的标识ID
             * 'digitInfo': 放音收号场景中,RTC业务平台对开发者进行放音收号操作的结果描述
             */
            if (array_key_exists('digitInfo', $statusInfo)) { // 你的业务逻辑
                $text = '【放音收号结构事件】---通话链路的标识ID:【'.$statusInfo['sessionId'].'】,呼叫事件发生时RTC业务平台的UNIX时间戳:【'.$statusInfo['timestamp'].'】,放音收号场景中,RTC业务平台对开发者进行放音收号操作的结果描述:【'.$statusInfo['digitInfo'].'】';
                ChargeOrderLogServices::createLog('语音通知',$text,$statusInfo['userData']);
            }
            return true;
        }
        // disconnect:挂机事件
        if (strcasecmp($eventType, 'disconnect') == 0) {
            /**
             * Example: 此处以解析sessionId为例,请按需解析所需参数并自行实现相关处理
             * 'timestamp': 该呼叫事件发生时RTC业务平台的UNIX时间戳
             * 'userData': 用户附属信息,语音通知api或语音回呼api携带的参数userData
             * 'sessionId': 通话链路的标识ID
             * 'caller': 主叫号码
             * 'called': 被叫号码
             * 'partyType': 挂机的用户类型,仅在语音回呼场景携带
             * 'stateCode': 通话挂机的原因值
             * 'stateDesc': 通话挂机的原因值的描述
             */
            if (array_key_exists('sessionId', $statusInfo)) { // 你的业务逻辑
                $text = '【挂机事件】---通话链路的标识ID:【'.$statusInfo['sessionId'].'】,呼叫事件发生时RTC业务平台的UNIX时间戳:【'.$statusInfo['timestamp'].'】,主叫号码:【'.$statusInfo['caller'].'】,被叫号码:【'.$statusInfo['called'].'】,通话挂机的原因值:【'.$statusInfo['stateCode'].'】,通话挂机的原因值的描述:【'.$statusInfo['stateDesc'].'】';
                ChargeOrderLogServices::createLog('语音通知',$text,$statusInfo['userData']);
            }
            return true;
        }
        return true;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值