<?php
/** 
 * 七牛直播
 * @Copyright (C) 2018 汉潮 All rights reserved.
 * @License http://www.hanchao9999.com
 * @Author xiaogg <xiaogg@sina.cn>
 */
namespace Common\Vendor;
class QiniuLive{
    private $USE_HTTPS = false;
    private $API_HOST = 'pili.qiniuapi.com';
    private $API_VERSION = 'v2';
    private $RTCAPI_HOST = 'http://rtc.qiniuapi.com';
    private $RTCAPI_VERSION = 'v2';   //连麦版本号，可以设置 "v1" 和 "v2"
    /**
     * 构造函数
     * @param array $config = array();
     */
    public function __construct($config){
        $this->config = !empty($this->config) && !empty($config)? array_merge($this->config, $config):!empty($config)?$config:$this->config;
        if(empty($this->config['accessKey']) || empty($this->config['secretKey']) || empty($this->config['BaseDomain']) || empty($this->config['hub'])){
            // $LiveSet=M('LiveSet')->where(1)->field('name,value')->cache(true)->select();
            // foreach($LiveSet as $v){$Liveconfig[$v['name']]=$v['value'];}
        }
        // if(empty($this->config['accessKey']))$this->config['accessKey']=$Liveconfig['live_qiniu_accessKey'];
        // if(empty($this->config['secretKey']))$this->config['secretKey']=$Liveconfig['live_qiniu_secretKey'];
        // if(empty($this->config['BaseDomain']))$this->config['BaseDomain']=$Liveconfig['live_vhost_name'];//基础域名
        
        if(empty($this->config['accessKey']))$this->config['accessKey']=getconfig('LIVE_QINIU_ACCESSKEY');
        if(empty($this->config['secretKey']))$this->config['secretKey']=getconfig('LIVE_QINIU_SECRETKEY');
        if(empty($this->config['BaseDomain']))$this->config['BaseDomain']=getconfig('LIVE_VHOST_NAME');//基础域名
        if(empty($this->config['PublishDomain']))$this->config['PublishDomain']='pili-publish'.$this->config['BaseDomain'];//推流域名
        if(empty($this->config['RtmpPlayDomain']))$this->config['RtmpPlayDomain']='pili-live-rtmp'.$this->config['BaseDomain'];//Rtmp播放域名
        if(empty($this->config['HlsPlayDomain']))$this->config['HlsPlayDomain']='pili-live-hls'.$this->config['BaseDomain'];//hls播放域名
        if(empty($this->config['HdlPlayDomain']))$this->config['HdlPlayDomain']='pili-live-hdl'.$this->config['BaseDomain'];//Hdl播放域名
        if(empty($this->config['SnapshotDomain']))$this->config['SnapshotDomain']='live-snapshot'.$this->config['BaseDomain'];//封面域名
        if(empty($this->config['hub']))$this->config['hub']=getconfig('LIVE_CONFIG_HUB');//默认直播空间名
    }
    /**
     * 生成 RTMP 推流地址.
     * @param $hub  直播空间名
     * @param $streamKey 流名
     * @param $expireAfterSeconds 有效期(秒) 表示 URL 在多久之后失效
     */
    public function RTMPPublishURL($streamKey, $hub='', $expireAfterSeconds=3600) {
        if(empty($hub))$hub=$this->config['hub'];
        $expire = NOW_TIME + $expireAfterSeconds;
        $path = sprintf("/%s/%s?e=%d", $hub, $streamKey, $expire);
        $token = $this->config['accessKey'] . ":" . $this->sign($path);
        return sprintf("rtmp://%s%s&token=%s", $this->config['PublishDomain'], $path, $token);
    }
    //生成 RTMP 直播地址.
    public function RTMPPlayURL($streamKey, $hub=''){
        if(empty($hub))$hub=$this->config['hub'];
        $url= sprintf("rtmp://%s/%s/%s", $this->config['RtmpPlayDomain'], $hub, $streamKey);
        return $this->encrypurl($url);
    }    
    //生成 HLS 直播地址.
    public function HLSPlayURL($streamKey, $hub=''){
        if(empty($hub))$hub=$this->config['hub'];
        $url= sprintf("http://%s/%s/%s.m3u8", $this->config['HlsPlayDomain'], $hub, $streamKey);
        return $this->encrypurl($url);
    }    
    //生成 HDL 直播地址.
    public function HDLPlayURL($streamKey, $hub=''){
        if(empty($hub))$hub=$this->config['hub'];
        $url= sprintf("http://%s/%s/%s.flv", $this->config['HdlPlayDomain'], $hub, $streamKey);
        return $this->encrypurl($url);
    }    
    //生成直播封面地址.
    public function SnapshotPlayURL($streamKey, $hub=''){
        if(empty($hub))$hub=$this->config['hub'];
        return sprintf("http://%s/%s/%s.jpg", $this->config['SnapshotDomain'], $hub, $streamKey);
    }
    /**
     * RETURN 查询直播状态.
     * @startAt: 直播开始的 Unix 时间戳, 0 表示当前没在直播.
     * @clientIP: 直播的客户端 IP.
     * @bps: 直播的码率.
     * @fps: 直播的帧率.
     */
    public function liveStatus($streamKey) {
        $url = $this->getbaseurl($streamKey) . "/live";        
        return $this->send($url);
    }
    /**
     * 禁播流
     * @param $streamKey 流名
     * @param $time 流禁播的结束时间戳，-1 表示永久禁播。0 表示解除禁播
     */
    public function liveDisabled($streamKey,$time=-1){
        $url = $this->getbaseurl($streamKey) . "/disabled";
        $param=array(
            'disabledTill'=>$time
        );
        return $this->send($url,'POST',$param);
    }
    
    /**
     * 录制直播回放
     * @param $streamKey 流名==房间名称
     * @param $fname 保存的文件名，不指定系统会随机生成
     * @param $start 保存的直播的起始时间戳 不指定或 0 值表示从第一次直播开始
     * @param $end 保存的直播的结束时间戳 不指定或 0 值表示从第一次直播开始
     * @param $format 保存的文件格式，默认为m3u8，如果指定其他格式，则保存动作为异步模式
     * @param $notify 异步模式时，保存成功回调通知地址
     * @param $pipeline 异步模式时，数据处理的私有队列，不指定则使用公共队列
     * @param $expireDays 更改ts文件的过期时间,默认为永久保存。-1 表示不更改ts文件的生命周期，正值表示修改ts文件的生命周期为expireDays
     */
    public function liveSaveas($streamKey,$fname='',$start='',$end='',$format='',$notify='',$pipeline='',$expireDays=''){
        $url = $this->getbaseurl($streamKey) . "/saveas";
        $param=array();
        if($fname)$param['fname']=$fname;
        if($start)$param['start']=$start;
        if($end)$param['end']=$end;
        if($format)$param['format']=$format;
        if($notify)$param['notify']=$notify;
        if($expireDays)$param['expireDays']=$expireDays;
        if($pipeline)$param['pipeline']=$pipeline;
        return $this->send($url,'POST',$param);
    }
    /**
     * PARAM 根据 prefix 遍历 Hub 的流列表.
     * @param $live 是否正在直播
     * @prefix: 流名的前缀.
     * @limit: 限定了一次最多可以返回的流个数, 实际返回的流个数可能小于这个 limit 值.
     * @marker: 是上一次遍历得到的流标.
     * RETURN
     * @keys: 流名的数组.
     * @omarker: 记录了此次遍历到的游标, 在下次请求时应该带上, 如果 omarker 为 "" 表示已经遍历完所有流.
     */
    public function listStreams($live='false',$prefix='', $limit='', $marker=''){
        $protocal = $this->USE_HTTPS === true ? "https" : "http";
        $baseURL = $protocal . "://" . $this->API_HOST . "/v2/hubs/" . $this->config['hub'];
        $url = sprintf("%s/streams?liveonly=%s&prefix=%s&limit=%d&marker=%s", $baseURL, $live, $prefix, $limit, $marker);
        return $this->send($url);
    }
    
    private function send($url,$method='GET',$body=null){
        $body=is_array($body)?json_encode($body):$body;
        $header =$this->_setHeaders($method,$url,$body);
        $opt=array(
            CURLOPT_FOLLOWLOCATION=>true,
            CURLOPT_MAXREDIRS=>10,
            CURLOPT_ENCODING=>'',
        );
        if($method!='GET')$opt[CURLOPT_CUSTOMREQUEST]='POST';
        $result=curlget($url,$body,$method,$header,true,true,$opt);
        return json_decode($result,1);
    }
    private function encrypurl($url,$auth_key='wanghai1',$time=300){
        $timestamp = NOW_TIME + $time;
        $t = $this->bc_dechex($timestamp);
        $urlarr = parse_url($url);
        $md5str = $auth_key . $urlarr['path'] . $t;
        $md5hash = md5($md5str);
        $urlparam = empty($urlarr['query']) ? '?' : '&';
        return $url . $urlparam . 'sign=' . $md5hash . '&t=' . $t;
    }
    private function bc_dechex($decimal){$result = [];
        while ($decimal != 0) {$mod = $decimal % 16;$decimal = floor($decimal / 16);array_push($result, dechex($mod));}
        return join(array_reverse($result));
    }
    private function getbaseurl($streamKey){
        $protocal = $this->USE_HTTPS === true ? "https" : "http";
        return sprintf("%s://%s/%s/hubs/%s/streams/%s", $protocal, $this->API_HOST, $this->API_VERSION, $this->config['hub'], $this->base64UrlEncode($streamKey));
    }
    private function sign($data){
        $digest=hash_hmac('sha1', $data, $this->config['secretKey'], true);
        return $this->base64UrlEncode($digest);
    }
    private function base64UrlEncode($str){
        $find = array('+', '/');
        $replace = array('-', '_');
        return str_replace($find, $replace, base64_encode($str));
    }
    private function _setHeaders($method, $url, $body = null){
        $cType = $method != 'GET'?'application/json':null;
        $macToken = $this->MACToken($method, $url, $cType, $body);
        $ua = $this->getUserAgent('pili-sdk-php','2.1.1');
        return array(
            'Content-Type: '. $cType,
            'User-Agent: '.$ua,
            'Authorization: ' .$macToken,
        );
    }
    private function getUserAgent($sdkName, $sdkVersion){
        $ua = sprintf("%s/%s", $sdkName, $sdkVersion);
        if (extension_loaded('curl')) {
            $curlVersion = curl_version();
            $ua .= ' curl/' . $curlVersion['version'];
        }
        $ua .= ' PHP/' . PHP_VERSION;
        return $ua;
    }
    private function MACToken($method, $url, $contentType, $body){
        $url = parse_url($url);
        $data = '';
        if (!empty($url['path'])) {$data = $method . ' ' . $url['path'];}
        if (!empty($url['query'])) {$data .= '?' . $url['query'];}
        if (!empty($url['host'])) {
            $data .= "\nHost: " . $url['host'];
            if (isset($url['port'])) {$data .= ':' . $url['port'];}
        }
        if (!empty($contentType)) {$data .= "\nContent-Type: " . $contentType;}
        $data .= "\n\n";
        if (!empty($body)) {$data .= $body;}
        return 'Qiniu ' . $this->config['accessKey'] . ':' . $this->sign($data);
    }
    //json返回
    private function ajaxReturn($data){
        echo json_encode($data);exit;
    }
}
?>