LiveService.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services;
  12. use AlibabaCloud\Tea\Exception\TeaUnableRetryError;
  13. use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
  14. use App\Models\LiveModel;
  15. use App\Models\MemberModel;
  16. use App\Services\Api\MemberCollectService;
  17. use Darabonba\OpenApi\Models\Config;
  18. use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
  19. use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
  20. use Illuminate\Support\Facades\DB;
  21. /**
  22. * 在线直播服务管理-服务类
  23. * @author laravel开发员
  24. * @since 2020/11/11
  25. * Class LiveService
  26. * @package App\Services
  27. */
  28. class LiveService extends BaseService
  29. {
  30. // 静态对象
  31. protected static $instance = null;
  32. /**
  33. * 构造函数
  34. * @author laravel开发员
  35. * @since 2020/11/11
  36. * ConfigService constructor.
  37. */
  38. public function __construct()
  39. {
  40. $this->model = new LiveModel();
  41. }
  42. /**
  43. * 静态入口
  44. * @return SmsService|static|null
  45. */
  46. public static function make()
  47. {
  48. if (!self::$instance) {
  49. self::$instance = new static();
  50. }
  51. return self::$instance;
  52. }
  53. public function getInfo($id, $userId)
  54. {
  55. $info = $this->model->with(['member'])->where(['id'=> $id,'mark'=>1])->first();
  56. if($info && isset($info['member'])){
  57. if(isset($info['member']['avatar'])){
  58. $info['member']['avatar'] = $info['member']['avatar']? $info['member']['avatar'] : '/images/member/logo.png';
  59. $info['member']['avatar'] = get_image_url($info['member']['avatar']);
  60. }
  61. if($info['user_id'] == $userId){
  62. $info['is_foolow'] = 1;
  63. }else{
  64. $checkFollow = MemberCollectService::make()->checkCollect($userId, $info['user_id'], 1);
  65. $info['is_follow'] = $checkFollow? 1 : 0;
  66. }
  67. // 观看权限
  68. $info['view_limit'] = 0;
  69. // 更新播放量
  70. if(!RedisService::get("caches:live:player:{$userId}_{$id}")){
  71. $this->model->where(['id'=> $id])->update(['views'=>DB::raw('views + 1'),'update_time'=>time()]);
  72. RedisService::set("caches:live:player:{$userId}_{$id}", ['user_id'=> $userId,'id'=>$id], rand(600, 1800));
  73. $info['views'] += 1;
  74. }
  75. }
  76. return $info;
  77. }
  78. /**
  79. * 获取直播推流/拉流地址
  80. * @param $streamName
  81. * @param string $appName
  82. * @param string $playType
  83. * @param int $expireTime
  84. * @return array
  85. */
  86. public function getLiveUrl($streamName, $appName = 'xlapp', $playType = 'rtmp', $expireTime = 1440)
  87. {
  88. $cachekey = "caches:live:urls:{$streamName}_{$appName}_{$playType}";
  89. $datas = RedisService::get($cachekey);
  90. if($datas){
  91. return $datas;
  92. }
  93. $playUrls = [];
  94. //未开启鉴权Key的情况下
  95. $pushDomain = ConfigService::make()->getConfigByCode('live_push_url');
  96. $playDomain = ConfigService::make()->getConfigByCode('live_play_url');
  97. $pushKey = ConfigService::make()->getConfigByCode('push_url_key');
  98. $playKey = ConfigService::make()->getConfigByCode('play_url_key');
  99. $timeStamp = time() + $expireTime * 60;
  100. if ($pushKey == '') {
  101. $pushUrl = 'rtmp://' . $pushDomain . '/' . $appName . '/' . $streamName;
  102. } else {
  103. $sstring = '/' . $appName . '/' . $streamName . '-' . $timeStamp . '-0-0-' . $pushKey;
  104. $md5hash = md5($sstring);
  105. $pushUrl = 'rtmp://' . $pushDomain . '/' . $appName . '/' . $streamName . '?auth_key=' . $timeStamp . '-0-0-' . $md5hash;
  106. }
  107. if ($playKey == '') {
  108. $playUrls['rtmp'] = 'rtmp://' . $playDomain . '/' . $appName . '/' . $streamName;
  109. $playUrls['flv'] = 'http://' . $playDomain . '/' . $appName . '/' . $streamName . '.flv';
  110. $playUrls['hls'] = 'http://' . $playDomain . '/' . $appName . '/' . $streamName . '.m3u8';
  111. } else {
  112. $rtmpSstring = '/' . $appName . '/' . $streamName . '-' . $timeStamp . '-0-0-' . $playKey;
  113. $rtmpMd5hash = md5($rtmpSstring);
  114. $playUrls['rtmp'] = 'rtmp://' . $playDomain . '/' . $appName . '/' . $streamName . '?auth_key=' . $timeStamp . '-0-0-' . $rtmpMd5hash;
  115. $flvSstring = '/' . $appName . '/' . $streamName . '.flv-' . $timeStamp . '-0-0-' . $playKey;
  116. $flvMd5hash = md5($flvSstring);
  117. $playUrls['flv'] = 'http://' . $playDomain . '/' . $appName . '/' . $streamName . '.flv?auth_key=' . $timeStamp . '-0-0-' . $flvMd5hash;
  118. $hlsSstring = '/' . $appName . '/' . $streamName . '.m3u8-' . $timeStamp . '-0-0-' . $playKey;
  119. $hlsMd5hash = md5($hlsSstring);
  120. $playUrls['hls'] = 'http://' . $playDomain . '/' . $appName . '/' . $streamName . '.m3u8?auth_key=' . $timeStamp . '-0-0-' . $hlsMd5hash;
  121. }
  122. $datas = [
  123. 'push_url' => $pushUrl,
  124. 'play_url' => isset($playUrls[$playType]) ? $playUrls[$playType] : '',
  125. 'play_urls' => $playUrls,
  126. ];
  127. RedisService::set($cachekey, $datas, 1800);
  128. return $datas;
  129. }
  130. /**
  131. * 创建直播间
  132. * @param $userId 直逼用户
  133. * @param $params
  134. * @return array|false
  135. */
  136. public function create($userId, $params)
  137. {
  138. $liveLevel = ConfigService::make()->getConfigByCode('live_open_level');
  139. $liveLevel = $liveLevel > 0 ? $liveLevel : 0;
  140. $userInfo = MemberModel::where(['id' => $userId, 'mark' => 1])->select(['id', 'nickname', 'member_level', 'status'])->first();
  141. $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
  142. $nickname = isset($userInfo['nickname']) ? $userInfo['nickname'] : '';
  143. $memberLevel = isset($userInfo['member_level']) ? $userInfo['member_level'] : 0;
  144. if (empty($userInfo) || $status != 1) {
  145. $this->error = 2024;
  146. return false;
  147. }
  148. if($memberLevel < $liveLevel){
  149. $this->error = 2040;
  150. return false;
  151. }
  152. // 验证是否有开播中断播的继续播
  153. $data = [
  154. 'type' => isset($params['type']) ? intval($params['type']) : 1,
  155. 'user_id' => $userId,
  156. 'title' => isset($params['title']) && $params['title'] ? trim($params['title']) : $nickname.'正在直播',
  157. 'description' => isset($params['description']) && $params['description'] ? trim($params['description']) : '我正在直播,快来看看吧',
  158. 'category' => isset($params['category']) ? intval($params['category']) : 0,
  159. 'visible_type' => isset($params['visible_type']) ? intval($params['visible_type']) : 0,
  160. 'visible_users' => isset($params['visible_users']) ? trim($params['visible_users']) : '',
  161. 'chat_type' => isset($params['chat_type']) ? intval($params['chat_type']) : 0,
  162. 'chat_status' => isset($params['chat_status']) ? intval($params['chat_status']) : 1,
  163. 'pay_status' => isset($params['pay_status']) ? intval($params['pay_status']) : 1,
  164. 'open_area' => isset($params['open_area']) ? intval($params['open_area']) : 1,
  165. 'view_allow' => isset($params['view_allow']) ? intval($params['view_allow']) : 1,
  166. 'push_url' => isset($params['push_url']) ? trim($params['push_url']) : '',
  167. 'play_url' => isset($params['play_url']) ? trim($params['play_url']) : '',
  168. 'update_time'=> time(),
  169. 'status' =>1,
  170. 'mark'=>1,
  171. ];
  172. if($liveId = $this->model->where(['user_id'=> $userId,'status'=>1,'mark'=>1])->orderBy('create_time','desc')->value('id')){
  173. if(!$this->model->where(['user_id'=> $userId,'status'=>1,'mark'=>1])->update($data)){
  174. $this->error = 2042;
  175. return false;
  176. }
  177. }else{
  178. $data['create_time'] = time();
  179. $this->model->where(['user_id'=> $userId,'mark'=>1])->update(['status'=>2,'update_time'=>time()]);
  180. if(!$liveId = $this->model->insertGetId($data)){
  181. $this->error = 2042;
  182. return false;
  183. }
  184. }
  185. $data['id'] = $liveId;
  186. $data['member'] = MemberModel::where(['id'=> $userId])->select(['id','nickname','avatar','status'])->first();
  187. $data['member'] = $data['member']? $data['member'] : [];
  188. $data['member']['is_follow'] = 1;
  189. if(isset($data['member']['avatar'])){
  190. $data['member']['avatar'] = $data['member']['avatar']? $data['member']['avatar'] : '/images/member/logo.png';
  191. $data['member']['avatar'] = get_image_url($data['member']['avatar']);
  192. }
  193. $this->error = 2041;
  194. return $data;
  195. }
  196. }