示例代码 - 直播
优质
小牛编辑
129浏览
2023-12-01
首先 声明一下,直播的前端代码是抄袭自http://www.workerman.net/camera 。本人并无鄙视workman的意思,只是为了告诉某些无脑喷,easySwoole也可以实现直播。
相关代码
更改easySwoole运行模式
修改/Conf/Config.php
"SERVER_TYPE"=>CoreSwooleConfig::SERVER_TYPE_WEB_SOCKET,//
注册相关事件
在Conf/Event.php的beforeWorkerStart事件中注册相关回调。
$server->on("message",function (swoole_websocket_server $server, swoole_websocket_frame $frame){
/*
* 注意 本example未引入redis来做fd信息记录,因此每次采用遍历的形式来获取结果,
* 仅供思路参考,不建议在生产环节使用
*/
$list = array();
foreach (Server::getInstance()->getServer()->connections as $connection){
$info = Server::getInstance()->getServer()->connection_info($connection);
if($info['websocket_status']){
$list[] = $connection;
}
}
$data = $frame->data;
AsyncTaskManager::getInstance()->add(function ()use($list,$data){
foreach ( $list as $fd) {
Server::getInstance()->getServer()->push($fd,$data);
}
});
});
$server->on("handshake",function (swoole_http_request $request, swoole_http_response $response){
//自定定握手规则,没有设置则用系统内置的(只支持version:13的)
if (!isset($request->header['sec-websocket-key']))
{
//'Bad protocol implementation: it is not RFC6455.'
$response->end();
return false;
}
if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
|| 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
)
{
//Header Sec-WebSocket-Key is illegal;
$response->end();
return false;
}
$key = base64_encode(sha1($request->header['sec-websocket-key']
. '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
true));
$headers = array(
'Upgrade' => 'websocket',
'Connection' => 'Upgrade',
'Sec-WebSocket-Accept' => $key,
'Sec-WebSocket-Version' => '13',
'KeepAlive' => 'off',
);
foreach ($headers as $key => $val)
{
$response->header($key, $val);
}
$response->status(101);
$response->end();
// Server::getInstance()->getServer()->push($request->fd,"hello world,your fd is ".$request->fd);
});
前端界面
/App/Static/camera.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>live cam 录像页面</title>
</head>
<body>
<video autoplay id="sourcevid" style="width:320;height:240px"></video>
<br>
提示:最好用火狐测试,谷歌浏览器升级了安全策略,谷歌浏览器只能在https下才能利用html5打开摄像头。
<canvas id="output" style="display:none"></canvas>
<script type="text/javascript" charset="utf-8">
var socket = new WebSocket("ws://"+document.domain+":9501");
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>
/App/Static/index.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>live cam 接收页面</title>
</head>
<body>
<img id="receiver" style="width:320px;height:240px"/>
<br><br>如果显示空白,说明当前没有人在直播,<a href="/camera.html" target="_blank">点击这里直播</a>
<script type="text/javascript" charset="utf-8">
var receiver_socket = new WebSocket("ws://"+document.domain+":9501");
var image = document.getElementById('receiver');
receiver_socket.onmessage = function(data)
{
image.src=data.data;
}
</script>
</body>
</html>
新建控制器
namespace AppController;
use CoreAbstractInterfaceAbstractController;
use CoreHttpMessageStatus;
class Index extends AbstractController
{
function index()
{
// TODO: Implement index() method.
$content = file_get_contents(ROOT."/App/Static/index.html");
$this->response()->write($content);
}
function onRequest($actionName)
{
// TODO: Implement onRequest() method.
}
function actionNotFound($actionName = null, $arguments = null)
{
// TODO: Implement actionNotFound() method.
$this->response()->withStatus(Status::CODE_NOT_FOUND);
}
function afterAction()
{
// TODO: Implement afterAction() method.
}
function camera(){
$content = file_get_contents(ROOT."/App/Static/camera.html");
$this->response()->write($content);
}
}
代码准备完毕
执行 php server start 启动easySwoole
注意:本代码仅为实例代码,展示了基础原理。未做房间号、缓存等处理,请勿用于生产环境