DetailController.class.php 8.31 KB
<?php
/**
 * 直播活动详情接口
 * Created by PhpStorm.
 * User: yingcai
 * Date: 2018/1/9
 * Time: 上午10:45
 */

namespace Api\Controller\Room;

use Com\LiveSDK;
use Common\Common\Constant;
use Common\Common\Order;
use Common\Common\User;
use Common\Service\MainService;
use Common\Service\ParticipateService;
use Common\Service\RangeService;
use Common\Service\RoleService;
use Common\Service\StudioFileService;
use Common\Service\StudioPlaybackService;
use Common\Service\StudioService;
use Org\Util\DistributedRedisLock;
use VcySDK\Enterprise;
use VcySDK\Service;

class DetailController extends AbstractController
{
    /**
     * Detail
     * @author houyingcai
     * @desc 直播活动详情接口
     * @param Int lm_id:true:1 直播活动ID
     * @return array|bool 直播列表
    array(
    'live_status' => 1, // 直播状态(1:草稿,2:未开始,3:进行中,4:已结束)
    'watched_total' => 123, // 当前进入直播间的人数
    'start_time' => 1515407868910, // 直播开始时间
    'name' => '产品培训讲解', // 直播名称
    'estimated_duration' => 45, // 预计时长(单位:分钟)
    'live_desc' => '直播描述', // 直播描述
    'pic' => 'b3ddbc502e307665f346cbd6e52cc10d', // 封面图ID
    'pic_url' => 'http://qy.vchangyi.org', // 封面图片URL
    'lecturer' => '王宇', // 讲师姓名
    'avatar' => 'http://qy.vchangyi.org', // 讲师头像URL
    'lecturer_title' => '金牌讲师', // 讲师头衔
    'lecturer_desc' => '讲师简介', // 讲师简介
    'end_time' => 12312312312, // 结束时间
    'has_playback' => true, // 是否有回放 true 有 false 无
    )
     */
    public function Index_post()
    {
        $lmId = I('post.lm_id', 0, 'rintval');

        // 直播ID不能为空
        if (!$lmId) {

            E('_EMPTY_LIVE_ID');
        }

        // 获取直播信息
        $mainService = new MainService();
        $mainDetail = $mainService->get($lmId);

        // 直播信息不存在
        if (empty($mainDetail)) {

            E('_ERR_LIVE_NOT_EXISTS');
        }

        // 获取讲师信息
        $roleService = new RoleService();
        $roleInfo = $roleService->get_by_conds([
            'lm_id' => $lmId
        ]);

        // 判断是否有观看权限
        $rangeService = new RangeService();
        $user = $this->_login->user;
        $checkRes = $rangeService->checkUserRange($user, $lmId);
        if (!$checkRes && $this->uid != $roleInfo['obj_id']) {

            E('_ERR_NOT_WATCHED_RANGE');
        }

        // 格式化直播状态
        $live_status = $mainService->live_status($mainDetail['live_status'], $mainDetail['start_time']);

        if ($roleInfo['type'] == Constant::LIVE_ROLE_TYPE_DEFAULT) {
            $lecturer = $roleInfo['obj_id'];
            // 系统管理员没有头像
            $avatar = '';
        } else {
            // 获取讲师个人信息
            $userService = &User::instance();
            $lecturerInfo = $userService->getByUid($roleInfo['obj_id']);
            $lecturer = $lecturerInfo['memUsername'];
            $avatar = $userService->avatar($roleInfo['obj_id'], $lecturerInfo);
        }

        // 先判断当前用户有没有观看记录
        $participateServ = new ParticipateService();
        $isParRes = $participateServ->count_by_conds([
            'lm_id' => $lmId,
            'obj_id' => $this->uid,
        ]);

        // 获取直播地址
        $liveSdk = new LiveSDK();
        $studioServ = new StudioService();
        $studioDetail = $studioServ->get_by_conds(['lm_id' => $mainDetail['lm_id']]);
        $playURLList = $liveSdk->getPlayUrl($studioDetail['stream_id']);
        $playUrl = $playURLList[2];

        // 初始化 Redis
        $redis = new \Redis();
        $redis->connect(cfg('REDIS_HOST'), cfg('REDIS_PORT'));
        if (cfg('REDIS_PWD')) {
            $redis->auth(cfg('REDIS_PWD'));
        }
        // 是否在线
        $userInRedisKey = 'Live_' . $lmId . '_USER_' . $this->uid;
        // 不在 在线列表内 并且 直播活动没有结束
        if (!$redis->exists($userInRedisKey) &&
            $mainDetail['live_status'] != Constant::LIVE_STATUS_OVER) {
            // 获取锁
            $redLock = new DistributedRedisLock([$redis], 500, 10);
            $lock = $redLock->lock('Live_' . $lmId . '_Lock_Update_Peak', 1000);
            if (!$lock) {
                E('_ERR_PLEASE_TRY_AGAIN_LATER');
            }

            // 获取当前在线人数
            $onlineMemberNum = count($redis->keys('Live_' . $lmId . '_USER_*'));
            // 获取峰值
            $redisKeyNamePeak = 'Live_' . $lmId . '_PEAK';
            $peakMemberNum = $redis->get($redisKeyNamePeak) ?: $mainDetail['online_peak'];

            // 在线人数超过峰值
            if ((++ $onlineMemberNum) > $peakMemberNum) {
                // isStandard -- 企业是否使用标准产品 : 0:非标准, 1:标准产品
                $sdk = new Enterprise(Service::instance());
                $epDetail = $sdk->detail();
                if (1 == $epDetail['isStandard']) {
                    // 扣减并发人数
                    $orderUtil = new Order();
                    $deductionsSuccess = $orderUtil->LiveCaseExpend([
                        'liveCastId' => $studioDetail['stream_id'],
                        'lcelSpendAmout' => 1
                    ]);
                    \Think\Log::record('扣减结果:::' . var_export($deductionsSuccess, true));
                    // 扣减失败
                    if (!$deductionsSuccess) {
                        E('_ERR_PLEASE_TRY_AGAIN_LATER');
                    }
                }

                // 单个用户进来只会增加一个峰值
                $redis->incr($redisKeyNamePeak);
                $redis->expire($redisKeyNamePeak, Constant::PEAK_SURVIVAL_TIME);
                // 增加峰值
                $mainService->update($lmId, ['online_peak = online_peak + ?' => 1]);
            }

            // 释放锁
            $redLock->unlock($lock);
        }
        // 算进在线人数内
        $redis->set($userInRedisKey, '', Constant::ONLINE_SURVIVAL_TIME);

        // 没有观看记录
        if (!$isParRes) {
            // 新增一条观看记录
            $insertData = [
                'lm_id' => $lmId,
                'obj_id' => $this->uid,
            ];
            $participateServ->insert($insertData);
            // 更新主表观看人数字段
            $mainService->update($lmId, ['watched_total = watched_total + ?' => 1]);

            $mainDetail['watched_total'] =  $mainDetail['watched_total'] + 1;
        } else {
            // 更新最后观看记录时间
            $participateServ->update_by_conds(
                [
                    'lm_id' => $lmId,
                    'obj_id' => $this->uid,
                ],
                ['updated' => MILLI_TIME]
            );
        }

        // 直播已经结束
        if ($mainDetail['live_status'] == Constant::LIVE_STATUS_OVER) {

            // 获取回放地址
            $studioPlayBackServ = new StudioPlaybackService();
            $playBackList = $studioPlayBackServ->list_by_conds(['lm_id' => $lmId]);
            if (!empty($playBackList)) {
                $playBackList = array_combine_by_key($playBackList, 'number');
                ksort($playBackList);
            }
            $playUrl = array_column($playBackList, 'sd');
        }

        // 返回数据
        $this->_result = [
            'live_status' => intval($live_status),
            'watched_total' => $mainDetail['watched_total'],
            'start_time' => $mainDetail['start_time'],
            'end_time' => $mainDetail['end_time'],
            'name' => $mainDetail['name'],
            'estimated_duration' => $mainDetail['estimated_duration'],
            'live_desc' => $mainDetail['desc'],
            'pic' => $mainDetail['pic'],
            'pic_url' => $mainService->formatCover($mainDetail['pic']),
            'lecturer' => $lecturer,
            'avatar' => $avatar,
            'lecturer_title' => $roleInfo['title'],
            'lecturer_desc' => $roleInfo['desc'],
            // 结束了回放
            'play_url' => $playUrl,
            // 是否有回放 true 有 false 无
            'has_playback' => !empty($playUrl),
            'push_total_time' => $mainDetail['push_total_time']
        ];

        return true;
    }
}