温馨提示微信小程序没有权限开通微信直播的可以用小程序嵌入web ,放个web即可观看直播哦
阿里播放器文档:https://player.alicdn.com/
1.添加推流域名和播流域名



播流的http头设置 一定要设置(不确定那个郁闷,跨域的可以先设置*



3. 关联推流和播流
在域名管理页面,选择您添加的播流域名,单击域名配置。
进入直播管理 > 基本配置页面,单击基础信息页签。
在此页面,您可以查看该域名的CNAME、创建时间、业务类型、直播中心、加速区域。
单击推流信息页签。
单击添加推流信息或推流域名后的编辑图标,选择需要关联的推流域名,并单击确定。
4.(可选)配置自定义鉴权(可选)
在视频直播控制台左侧导航栏,单击域名管理,进入域名管理页面。
选择您要配置的播流域名,单击域名配置。
单击直播管理 > 访问控制,并选择URL鉴权页签,单击修改配置。
配置URL鉴权信息,单击确定。
配置项和说明如下表所示。
温馨提示:一般的地址rtmp,超低延时的播放地址只是前面协议是artc(开启H5转码哦),
5.生成推流地址和播流地址

composer require alibabacloud/live
7. 2 实现代码
Alive.php
<?php
// TTTTTTTTTTTTTTTTTTTTTTT                  MMMMMMMM               MMMMMMMM                                CCCCCCCCCCCCMMMMMMMM               MMMMMMMM  SSSSSSSSSSSSSSS 
// T:::::::::::::::::::::T                  M:::::::M             M:::::::M                             CCC::::::::::::M:::::::M             M:::::::MSS:::::::::::::::S
// T:::::::::::::::::::::T                  M::::::::M           M::::::::M                           CC:::::::::::::::M::::::::M           M::::::::S:::::SSSSSS::::::S
// T:::::TT:::::::TT:::::T                  M:::::::::M         M:::::::::M                          C:::::CCCCCCCC::::M:::::::::M         M:::::::::S:::::S     SSSSSSS
// TTTTTT  T:::::T  TTTTTppppp   ppppppppp  M::::::::::M       M::::::::::M   eeeeeeeeeeee          C:::::C       CCCCCM::::::::::M       M::::::::::S:::::S            
//         T:::::T       p::::ppp:::::::::p M:::::::::::M     M:::::::::::M ee::::::::::::ee       C:::::C             M:::::::::::M     M:::::::::::S:::::S            
//         T:::::T       p:::::::::::::::::pM:::::::M::::M   M::::M:::::::Me::::::eeeee:::::ee     C:::::C             M:::::::M::::M   M::::M:::::::MS::::SSSS         
//         T:::::T       pp::::::ppppp::::::M::::::M M::::M M::::M M::::::e::::::e     e:::::e     C:::::C             M::::::M M::::M M::::M M::::::M SS::::::SSSSS    
//         T:::::T        p:::::p     p:::::M::::::M  M::::M::::M  M::::::e:::::::eeeee::::::e     C:::::C             M::::::M  M::::M::::M  M::::::M   SSS::::::::SS  
//         T:::::T        p:::::p     p:::::M::::::M   M:::::::M   M::::::e:::::::::::::::::e      C:::::C             M::::::M   M:::::::M   M::::::M      SSSSSS::::S 
//         T:::::T        p:::::p     p:::::M::::::M    M:::::M    M::::::e::::::eeeeeeeeeee       C:::::C             M::::::M    M:::::M    M::::::M           S:::::S
//         T:::::T        p:::::p    p::::::M::::::M     MMMMM     M::::::e:::::::e                 C:::::C       CCCCCM::::::M     MMMMM     M::::::M           S:::::S
//       TT:::::::TT      p:::::ppppp:::::::M::::::M               M::::::e::::::::e                 C:::::CCCCCCCC::::M::::::M               M::::::SSSSSSS     S:::::S
//       T:::::::::T      p::::::::::::::::pM::::::M               M::::::Me::::::::eeeeeeee          CC:::::::::::::::M::::::M               M::::::S::::::SSSSSS:::::S
//       T:::::::::T      p::::::::::::::pp M::::::M               M::::::M ee:::::::::::::e            CCC::::::::::::M::::::M               M::::::S:::::::::::::::SS 
//       TTTTTTTTTTT      p::::::pppppppp   MMMMMMMM               MMMMMMMM   eeeeeeeeeeeeee               CCCCCCCCCCCCMMMMMMMM               MMMMMMMMSSSSSSSSSSSSSSS   
//                        p:::::p                                                                                                                                       
//                        p:::::p                                                                                                                                       
//                       p:::::::p                                                                                                                                      
//                       p:::::::p                                                                                                                                      
//                       p:::::::p                                                                                                                                      
//                       ppppppppp                                                                                                                                      
//  _____      __  __         ____ __  __ ____  
// |_   __ __ |  \/  | ___   / ___|  \/  / ___|     | AUTHOR: Xiaohe
//   | || '_ \| |\/| |/ _ \ | |   | |\/| \___ \     | EMAIL: 496631085@qq.com
//   | || |_) | |  | |  __/ | |___| |  | |___) |    | WECHAT: he4966
//   |_|| .__/|_|  |_|\___|  \____|_|  |_|____/     | DATETIME: 2022/10/10
//      |_|                                         | TpMeCMS
namespace app\api\controller;
// namespace App\Server;
use app\api\controller\Tpmecms;
use think\Config;
use think\Db;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
 
class Alive extends Tpmecms
{
    private $error;
    const DOMAIN_NAME = 'tlive.he4966.cn';//你的加速域名,和推流域名一致。
    const REGION_ID = 'cn-shanghai';//区域
    const ACCESS_KEY_ID = 'LTAI5tELmApeQDxVpsH0RJHN';//阿里云秘钥
    const ACCESS_KEY_SECRET = 'f42T02z8YUYqxI6rBxc0FTJ6EzBFbw';//阿里云秘钥
    const LIVE_HOST = 'live.aliyuncs.com';//写死,阿里云直播CDN域名
    const ALIVE_URL = 'tlive.he4966.cn';//推域名
    const ALIVE_KEY = '8N0he4n2LlPsVMUb';        //推流鉴权KEY,后台拿
    const TLIVE_URL = 'alive.he4966.cn';//关联的播域名
    const TLIVE_KEY = 'TsLU5Rz9paNg24b9';    //播流鉴权KEY,后台拿
    public function _initialize()
    {
        parent::_initialize();
    }
 
    
        //创建推流
        $path="/$appName/$streamName";
        $aliveUrl='rtmp://'.self::ALIVE_URL."$path?".self::createSign($path,$endTime,self::ALIVE_KEY);
 
        //创建播流
        $rtmp_sstring = '/'.$appName.'/'.$streamName.'-'.$endTime.'-0-0-'.self::TLIVE_KEY;
        $rtmp_md5hash = md5($rtmp_sstring);
        $play_url = '://'.self::TLIVE_URL.'/'.$appName.'/'.$streamName.'?auth_key='.$endTime.'-0-0-'.$rtmp_md5hash;
        $rtmp_play_url = 'rtmp'.$play_url;
        $artc_play_url = 'artc'.$play_url;//超低延迟播放地址
        $flv_sstring = '/'.$appName.'/'.$streamName.'.flv-'.$endTime.'-0-0-'.self::TLIVE_KEY;
        $flv_md5hash = md5($flv_sstring);
        $flv_play_url = '//'.self::TLIVE_URL.'/'.$appName.'/'.$streamName.'.flv?auth_key='.$endTime.'-0-0-'.$flv_md5hash;//其他域名里播放请添加 HTTP头配置 Access-Control-Allow-Origin为*
 
        $hls_sstring = '/'.$appName.'/'.$streamName.'.m3u8-'.$endTime.'-0-0-'.self::TLIVE_KEY;
        $hls_md5hash = md5($hls_sstring);
        $hls_play_url = '//'.self::TLIVE_URL.'/'.$appName.'/'.$streamName.'.m3u8?auth_key='.$endTime.'-0-0-'.$hls_md5hash;//其他域名里播放请添加 HTTP头配置 Access-Control-Allow-Origin为*
  
        $data = [
            'rtmp'=>$rtmp_play_url,
            'flv'=>$flv_play_url,
            'hls'=>$hls_play_url,
            'artc'=>$artc_play_url,
        ];
        return [
            'alive_url'=>$aliveUrl,
            'tlive_url'=>$data,
        ];
    /**
     * 创建签名
     * @param $path 播放地址 域名后面所有
     * @param $exp //结束时间
     * @param $key
     * @return string
     */
    private static function createSign($path,$exp,$key)
    {
        $rand=0;
        $uid=0;
        $str=sprintf("%s-%s-%s-%s-%s",$path,(string)$exp,(string)$rand,(string)$uid,$key);
        $hashValue=md5($str);
        $authKey=sprintf("%s-%s-%s-%s",(string)$exp,(string)$rand,(string)$uid,$hashValue);
        return "auth_key=$authKey";
    }
    /**
     * 停止直播
     *
     * @param string $appName app名
     * @param string $streamName 房间ID
     * @return void
     */
    public static function stopLive($appName,$streamName)
    {
        $query=[
            'RegionId' => self::REGION_ID,
            'AppName' => $appName,
            'StreamName' => $streamName,
            'LiveStreamType' => "publisher",
            'DomainName' => self::DOMAIN_NAME,
            // 'ResumeTime'=>'',
        ];
        $_this=new static();
        $result=$_this->request('ForbidLiveStream',$query);
        return $result;
    }
    /**
     * 恢复直播
     *
     * @param string $appName app名
     * @param string $streamName 房间ID
     * @return void
     */
    public static function resumeLive($appName,$streamName)
    {
        $query=[
            'RegionId' => self::REGION_ID,
            'LiveStreamType' => "publisher",
            'AppName' => $appName,
            'StreamName' => $streamName,
            'DomainName' => self::DOMAIN_NAME,
        ];
        $_this=new static();
        $result=$_this->request('ResumeLiveStream',$query);
        return $result;
    }
    
    /**
     * 获取直播在线人数
     *
     * @param string $appName app名
     * @param string $streamName 房间ID
     * @return void
     */
    public static function getOnlineUserNum($appName,$streamNma)
    {
        $query=[
            'RegionId' => self::REGION_ID,
            'DomainName' => self::DOMAIN_NAME,
            'AppName'=>$appName,
            'StreamName' =>$streamNma,
        ];
        $_this=new static();
        $result=$_this->request('DescribeLiveStreamOnlineUserNum',$query);
        return $result;
    }
    //获取错误
    public static function getError()
    {
        return (new static())->error;
    }
    
    //请求
    private function request($action,Array $query)
    {
        AlibabaCloud::accessKeyClient(self::ACCESS_KEY_ID, self::ACCESS_KEY_SECRET)
            ->regionId(self::REGION_ID)
            ->asDefaultClient();
        try {
            $result = AlibabaCloud::rpc()
                ->product('live')
                 ->scheme('https') // https | http
                ->version('2016-11-01')
                ->action($action)
                ->method('POST')
                ->host(self::LIVE_HOST)
                ->options([
                    'query' => $query,
                ])
                ->request();
            return $result->toArray();
        } catch (ClientException $e) {
            $this->error=$e->getMessage();
            return false;
        } catch (ServerException $e) {
            $this->error=$e->getMessage();
            return false;
        }
    }
    /**
     * 回掉
     *
     * @return void
     */
    public function callback()
    {   
        $param = $this->request->param();
        //日志 可以自行查看调试日志
        file_put_contents($param['action'].'.txt',date('Y-m-d-H-I-s').json_encode($param).PHP_EOL,FILE_APPEND);
        switch ($param['action']) {
            case 'publish'://推送直播
                //{"action":"publish","ip":"58.214.16.27","id":"4","app":"tlive.he4966.cn","appname":"alive","time":"1665390204","usrargs":"vhost=alive.he4966.cn&auth_key=1665391198-0-0-10c534811ba5246ef078d5c616f70baf&ali_publisher_ip=58.214.16.27&ali_edge_node_ip=222.187.253.227&ali_node_via=cache27.cn5063%2clive11.l2et117&ali_node_ip=222.187.253.201#26%2c47.102.18.31#6&alilive_streamidv2=27.cn5063_40801_1246404453_1665390202202&alilive_clienthost=live11.l2et117","node":"222.187.253.227","width":"0","height":"0"}
                $where['app_name'] = $param['appname'];
                $where['id'] = $param['id'];
                $update['ip'] = $param['ip'];
                $update['live_status'] = '1';//直播状态:1=直播中,2=未开始,3=已结束,4=禁播,5=暂停中,6=异常,7=已过期
                Db::name('alive')->where($where)->update($update);
                break;
            case 'publish_done'://推送结束
                //{"action":"publish_done","ip":"58.214.16.27","id":"4","app":"tlive.he4966.cn","appname":"alive","time":"1665390255","usrargs":"vhost=alive.he4966.cn&auth_key=1665391198-0-0-10c534811ba5246ef078d5c616f70baf&ali_publisher_ip=58.214.16.27&ali_edge_node_ip=222.187.253.227&ali_node_via=cache27.cn5063%2clive11.l2et117&ali_node_ip=222.187.253.201#26%2c47.102.18.31#6&alilive_streamidv2=27.cn5063_40801_1246404453_1665390202202&alilive_clienthost=live11.l2et117","node":"222.187.253.227","width":"0","height":"0"}
                $where['app_name'] = $param['appname'];
                $where['id'] = $param['id'];
                // $update['ip'] = $param['ip'];
                $update['live_status'] = '3';//直播状态:1=直播中,2=未开始,3=已结束,4=禁播,5=暂停中,6=异常,7=已过期
                Db::name('alive')->where($where)->update($update);
                break;
                
            default:
                
                break;
        }
  
    }
    /**
     * 获取直播列表
     *
     * @param string $live_status 直播状态:1=直播中,2=未开始,3=已结束,4=禁播,5=暂停中,6=异常,7=已过期
     * @return void
     */
    public function get_live_list($live_status=null)
    {
        $where = null;
        if($live_status)
            $where['live_status'] = $live_status;
        $list = Db::name('alive')->where($where)->select();
        if($list){
            foreach ($list as $key => &$val) {
                
                $val['start_date'] = date('Y-m-d H:i',$val['start_time']);
                $val['end_date'] = date('Y-m-d H:i',$val['end_time']);
            }
        }
        $this->success('ok',$list);
    }
    // /**
    //  * 创建直播
    //  *
    //  * @param string $name 房间
    //  * @param string $number 房间id
    //  * @param string $end_date 结束时间
    //  * @return void
    //  */
    // public function add_live($name=null,$number=null,$end_date=null)
    // {
    //     if($end_date){
    //         $end_time = strtotime($end_date);
    //     }else{
    //         $this->error('亲传递结束时间');
    //     }
        
    //     $data = self::createdLive($name,$number,$end_time);
    //     //
    //     $this->success('ok',$data);
    // }
 
}
alive.sql 数据库
CREATE TABLE `fa_alive` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '房间ID',
  `name` varchar(255) DEFAULT NULL COMMENT '直播房间名',
  `app_name` varchar(255) NOT NULL DEFAULT 'alive' COMMENT 'APP名',
  `start_time` int(10) NOT NULL COMMENT '直播计划开始时间',
  `end_time` int(10) NOT NULL COMMENT '直播计划结束时间',
  `description` varchar(255) DEFAULT NULL COMMENT '直播简介',
  `image` varchar(255) DEFAULT NULL COMMENT '直播封面图',
  `alive_url` varchar(255) DEFAULT NULL COMMENT '推流地址',
  `tlive_json` varchar(2555) DEFAULT NULL COMMENT '拉流JSON',
  `rtmp_url` varchar(255) DEFAULT NULL COMMENT 'rtmp拉流地址',
  `flv_url` varchar(255) DEFAULT NULL COMMENT 'flv拉流地址',
  `hls_url` varchar(255) DEFAULT NULL COMMENT 'hls拉流地址',
  `time` int(10) unsigned DEFAULT NULL COMMENT '创建时间',
  `live_status` enum('1','2','3','4','5','6','7') DEFAULT '2' COMMENT '直播状态:1=直播中,2=未开始,3=已结束,4=禁播,5=暂停中,6=异常,7=已过期',
  `ip` varchar(20) DEFAULT NULL COMMENT '直播IP',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='阿里直播';
前段控制器代码 访问地址传入参数id=
    /**
     * 查看直播
     *
     * @param int $id 房间ID
     * @return void
     */
    public function live($id=null)
    {
        $data = Db::name('alive')->where('id',$id)->find();
        if(!$data){
            $this->error('没有该直播间');
        }
        $title = $data['name'];
        //直播状态:1=直播中,2=未开始,3=已结束,4=禁播,5=暂停中,6=异常,7=已过期
        $error = ['1'=>'直播中','2'=>'未开始','3'=>'已结束','4'=>'禁播','5'=>'暂停中','6'=>'异常','7'=>'已过期'];
        switch ($data['live_status']) {
            case '1':
                
                break;
            
            default:
                // $this->error($error[$data['live_status']]);
                $title = $error[$data['live_status']];
                break;
        }
        $this->view->assign('title', $title);//
        $this->view->assign('data', $data);//
        return $this->view->fetch();
    }
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge" >
    <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
    <title>{$title}</title>
    <link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.16/skins/default/aliplayer-min.css" />
    <script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.9.16/aliplayer-min.js"></script>
</head>
<body>
<div class="prism-player" id="player-con"></div>
<script>
    var player = new Aliplayer({
            "id": "player-con",
        //M3U8格式使用
            "source": "{$data.hls_url}",
            "width": "100%",
            "height": "500px",
            "autoplay": true,
            //直播参数必须为true
            "isLive": true,
            "rePlay": false,
            "playsinline": true,
            "preload": true,
            {if $data.image}"cover":'{$data.image}',{/if}
            "controlBarVisibility": "hover",
            "useH5Prism": true
            
        }, function (player) {
            console.log("The player is created");
        }
    );
</script>
</body>
超低延迟直播
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge" >
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<title>{$title}</title>
<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.9.23/skins/default/aliplayer-min.css" />
<script type="text/javascript" charset="utf-8" src="https://g.alicdn.com/de/prismplayer/2.9.23/aliplayer-min.js"></script>
</head>
<style>
	*{
		margin: 0;
		padding: 0;
		list-style: none;
	}
	.prism-player{
		width: 100%;
		height: 100%;
	}
</style>
<body>
  <div class="prism-player" id="player-con"></div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
    var hh = $(window).height();
	console.log(hh);
	$('.prism-player').css('height',hh+'px');
  /**
   * 播放器默认播放 source 提供的 rts 拉流地址,如果失败,则会自动降级至 rtsFallbackSource 提供的拉流地址(如 HLS 地址)。
   * 可能的降级场景包括:
   * 1. 浏览器不支持 RTS,直接降级
   * 2. RTS 信令请求失败(拉流地址无效、https配置无效、RTS配置无效等),直接降级
   * 3. RTS 起播超时或中途断流,按自定义策略重试失败后降级
   **/
  // 更多播放器配置请参考 https://player.alicdn.com/aliplayer/index.html
  var options = {
    "id": "player-con",
    "source": "{$data.artc_url}",
    "rtsFallbackSource": "https:{$data.hls_url}",
    // "source": "RTS播放地址",
    // "rtsFallbackSource": "降级地址,如HLS",
    "width": "100%",
    "height": "500px",
    {if $data.image}"cover":'{$data.image}',{/if}
    "autoplay": true,
    "isLive": true,
    "playsinline": true,
    "useH5Prism": true,
    "skipRtsSupportCheck": false, // 对于不在 https://help.aliyun.com/document_detail/397569.html 中的浏览器,可以传 true 跳过检查,强制使用 RTS(有风险,需要自测保证)
    /**
     * RTS 拉流超时会默认重试
     * 以下两个参数用来控制降级之前的重试策略,比如 3000 毫秒超时,重试一次,如果再拉不到流就降级,那么总共等待 6000 毫秒降级
     **/
    // RTS 多久拉不到流会重试,默认 3000 ms
    // rtsLoadDataTimeout: 2000,
    // RTS 拉不到流重试的次数,默认 5,此参数建议设为 1,即重试 1 次后降级,可以减少降级等待时间
    liveRetry: 2,
  };
  var player = new Aliplayer(options, function () {
    /* player ready */
    });
  // 降级时会触发此事件
  player.on('rtsFallback', function(event) {
    console.log('[EVENT]rtsFallback', event.paramData);
    // event.paramData.reason 降级的原因
    // event.paramData.fallbackUrl 降级到的地址
  })
  player.on('error', function(event) {
    console.log('[EVENT]error', event.paramData);
  })
</script>
</body>
