温馨提示微信小程序没有权限开通微信直播的可以用小程序嵌入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>