基于 swoole 通过 websocket 简单实现直播效果。(主要学习一下 websocket 相关知识点)
流程
- 在直播页使用视频的方式模拟摄像头
- 利用 canvas 绘制视频内容
- 通过 canvas 将绘制的图片转化为 base64 格式
- 使用 settimeout 定时执行,通过 websocket 将 base64 格式图片传递到服务端
- 服务端接收到数据之后,通过广播的形式进行推送
- 客户端页面通过 websocket 接收服务端发来的数据在页面上循环展示
- 完成
直播页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<video src="xszr.mp4" id="video" width="400" height="400" autoplay="true" controls="true"></video>
<canvas id="canvas" width="1280" height="720" hidden></canvas>
<script>
ws = new WebSocket("ws://test.test/ws");
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
function draw() {
context.drawImage(video,0,0);
ws.send(canvas.toDataURL('image/jpeg',0.4));
setTimeout(draw,80);
}
ws.onopen = function (event) {
draw();
}
</script>
</body>
</html>
websocket 服务端
$ws = new swoole_websocket_server('0.0.0.0',9527);
//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) {
var_dump($ws->connections);
foreach ($ws->connections as $fd){
$ws->push($fd,$frame->data);
}
});
//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$ws->start();
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img id="img" width="1280" height="720" />
<script>
ws = new WebSocket("ws://test.test/ws");
img = document.getElementById('img');
ws.onmessage = function (event) {
img.src = event.data
}
</script>
</body>
</html>
最终效果
nginx 配置
upstream test {
# 因为使用的laradock 所以是workspace,其他环境根据具体情况填写对应 ip 地址
server workspace:9527 weight=5 max_fails=3 fail_timeout=30s;
keepalive 16;
}
server {
listen 80;
server_name test.test;
root /var/www/test;
index index.php index.html index.htm;
# 因为 laradock 开启其他端口比较麻烦,所以使用该方法进行转发
location =/ws {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://test;
}
}