以下是源码,memcache和workerman实现,基于websocker长链接
前端代码主播页面
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>直播表演 录像页面</title>
</head>
<body>
<div class="box">
<div class="gift">
<video autoplay id="sourcevid" style="width:320;height:240px"></video>
<canvas id="output" style="display:none"></canvas>
</div>
</div>
</div>
<script src="../show/js/sea.js"></script>
<script src="../show/js/jquery.min.js?v=2.1.4"></script>
<script src="../show/js/bootstrap.min.js?v=3.3.6"></script>
<script>
seajs.config({
alias:{
'jquery':'../show/js/jquery.js'
}
})
seajs.use('../show/js/main.js')
</script>
<script type="text/javascript" charset="utf-8">
var socket = new WebSocket("ws://"+document.domain+":8080");
var back = document.getElementById('output');
var backcontext = back.getContext('2d');
var video = document.getElementsByTagName('video')[0];
var success = function(stream){
video.src = window.URL.createObjectURL(stream);
}
socket.onopen = function(){
draw();
}
var draw = function(){
try{
backcontext.drawImage(video,0,0, back.width, back.height);
}catch(e){
if (e.name == "NS_ERROR_NOT_AVAILABLE") {
return setTimeout(draw, 100);
} else {
throw e;
}
}
if(video.src){
socket.send(back.toDataURL("image/jpeg", 0.5));
}
setTimeout(draw, 100);
}
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
navigator.getUserMedia({video:true, audio:false}, success, console.log);
</script>
</body>
</html>
游客观看页面
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>游客观看页面</title>
</head>
<style>
#receiver{
margin: 0 500px ;
}
.al{
margin: 0 500px ;
}
</style>
<body>
<img id="receiver" style="width:320px;height:240px"/>
<br><br><h1 class="a1">如果显示空白,说明当前没有人在直播</h1>
<!--<a class="a1" href="/camera.html" target="_blank">点击这里直播</a>-->
<script type="text/javascript" charset="utf-8">
var receiver_socket = new WebSocket("ws://"+document.domain+":8008");
var image = document.getElementById('receiver');
receiver_socket.onmessage = function(data)
{
image.src=data.data;
}
receiver_socket.onopen = function()
{
receiver_socket.send(<?=$_GET['zhuboId']?>); //有个主播列表页面 接受 主播id
}
</script>
</body>
</html>
workerman start_worker.php后台逻辑处理
use \Workerman\Worker;
use \Workerman\Protocols\Websocket;
require_once __DIR__ . '/vendor/autoload.php';
$mem = new Memcache();
$mem->connect('127.0.0.1','11211');
$recv_worker = new Worker('Websocket://0.0.0.0:8080'); //主播的
$recv_worker->onWorkerStart = function($recv_worker)use($mem)
{
$send_worker = new Worker('Websocket://0.0.0.0:8008'); //游客的
$send_worker->onMessage = function($connection, $data)use($mem)
{
//当观看者与服务器创建ws之后,并且服务器端接受到观看者发过来的信息(请求):
//“观看者要求观看主播的id”
//$data 主播id
//$connection->id 观看者id
$client_num = $mem->get('client_num');
if(empty($client_num))
{
$client_num = [];
}
$client_num[$data][] = $connection->id;
$mem->set('client_num',$client_num);
// $mem->set('zhubo',$data);
};
//游客离开事件
$send_worker->onClose = function($connection)use($mem)
{
$client_num = $mem->get('client_num');
foreach($client_num as $k=>$v)
{
if(in_array($connection->id,$v)){
unset($v[$connection->id]);
}
}
$mem->set('client_num',$client_num);
};
$recv_worker->sendWorker = $send_worker;
$send_worker->listen();
};
$recv_worker->onMessage = function($connection, $data)use($recv_worker,$mem)
{
/*
* 1.当主播的页面与后台的ws 建立 链接时 后台可以接受到主播发送过来的消息 我就认为他是 主播 并且给他一个主播id
*/
$zhubo_id_arr = $mem->get('zhubo_id_arr');
if(empty($zhubo_id_arr)){
$zhubo_id_arr = array($connection->id=>1);
} else {
$zhubo_id_arr[$connection->id] = 1;
}
$mem->set('zhubo_id_arr',$zhubo_id_arr);
$client_num = $mem->get('client_num');
$client = $client_num[$connection->id];
foreach($recv_worker->sendWorker->connections as $k=>$send_connection)
{
//$send_connection->websocketType = "\x82";
if(in_array($k,$client)){
$send_connection->send($data);
}
}
};
//主播离开事件
$recv_worker->onClose = function($connection)use($mem)
{
$zhubo_id_arr = $mem->get('zhubo_id_arr');
unset($zhubo_id_arr[$connection->id]);
$mem->set('zhubo_id_arr',$zhubo_id_arr);
$client_num = $mem->get('client_num');
unset($client_num[$connection->id]);
$mem->set('client_num',$client_num);
};
// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
php启动
如果有什么问题,请留下联系方式,博主会与你联系,共同进步