Swoole 实践篇之结合 WebRTC 实现音视频实时通信方案

2024-04-17 04:12

本文主要是介绍Swoole 实践篇之结合 WebRTC 实现音视频实时通信方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文首发链接:Swoole 实践篇之结合 WebRTC 实现音视频实时通信方案
大家好,我是码农先森。

引言

这次实现音视频实时通信的方案是基于 WebRTC 技术的,它是一种点对点的通信技术,通过浏览器之间建立对等连接,实现音频和视频流数据的传输。

在 WebRTC 技术中通常使用 WebSocket 服务来协调浏览器之间的通信,建立 WebRTC 通信的信道,传输通信所需的元数据信息,如:SDP、ICE 候选项等。

WebRTC 技术在实时通信领域中得到了广泛应用,包括在线会议、视频聊天、远程协作等,例如:腾讯在线会议就是基于此技术实现的。

技术实现

index.html 作为首页,这里提供了发起方、接收方的操作入口。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>p2p webrtc</title><style>.container {width: 250px;margin: 100px auto;padding: 10px 30px;border-radius: 4px;border: 1px solid #ebeef5;box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);color: #303133;}</style>
</head>
<body><div class="container"><p>流程:</p><ul><li>打开<a href="/p2p?type=answer" target="_blank">接收方页面</a>;</li><li>打开<a href="/p2p?type=offer" target="_blank">发起方页面</a>;</li><li>确认双方都已建立 WebSocket 连接;</li><li>发起方点击 开始 按钮。</li></ul></div>
</body>
</html>

p2p.html 作为视频展示页面,且实现了调取摄像头及音频权限的功能,再将连接数据推送到 WebSocket 服务端,最后渲染远程端的音视频数据到本地。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title></title><style>* {padding: 0;margin: 0;box-sizing: border-box;}.container {width: 100%;display: flex;display: -webkit-flex;justify-content: space-around;padding-top: 20px;}.video-box {position: relative;width: 330px;height: 550px;}#remote-video {width: 100%;height: 100%;display: block;object-fit: cover;border: 1px solid #eee;background-color: #F2F6FC;}#local-video {position: absolute;right: 0;bottom: 0;width: 140px;height: 200px;object-fit: cover;border: 1px solid #eee;background-color: #EBEEF5;}.start-button {position: absolute;left: 50%;top: 50%;width: 100px;display: none;line-height: 40px;outline: none;color: #fff;background-color: #409eff;border: none;border-radius: 4px;cursor: pointer;transform: translate(-50%, -50%);}</style>
</head>
<body><div class="container"><div class="video-box"><video id="remote-video"></video><video id="local-video" muted></video><button class="start-button" onclick="startLive()">开始</button></div></div><script>const target = location.search.slice(6);const localVideo = document.querySelector('#local-video');const remoteVideo = document.querySelector('#remote-video');const button = document.querySelector('.start-button');localVideo.onloadeddata = () => {console.log('播放本地视频');localVideo.play();}remoteVideo.onloadeddata = () => {console.log('播放对方视频');remoteVideo.play();}document.title = target === 'offer' ? '发起方' : '接收方';console.log('信令通道(WebSocket)创建中......');const socket = new WebSocket('ws://127.0.0.1:9502');socket.onopen = () => {console.log('信令通道创建成功!');target === 'offer' && (button.style.display = 'block');}socket.onerror = () => console.error('信令通道创建失败!');socket.onmessage = e => {const { type, sdp, iceCandidate } = JSON.parse(e.data)if (type === 'answer') {peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));} else if (type === 'answer_ice') {peer.addIceCandidate(iceCandidate);} else if (type === 'offer') {startLive(new RTCSessionDescription({ type, sdp }));} else if (type === 'offer_ice') {peer.addIceCandidate(iceCandidate);}};const PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;!PeerConnection && console.error('浏览器不支持WebRTC!');const peer = new PeerConnection();peer.ontrack = e => {if (e && e.streams) {console.log('收到对方音频/视频流数据...');remoteVideo.srcObject = e.streams[0];}};peer.onicecandidate = e => {if (e.candidate) {console.log('搜集并发送候选人');socket.send(JSON.stringify({type: `${target}_ice`,iceCandidate: e.candidate}));} else {console.log('候选人收集完成!');}};async function startLive (offerSdp) {target === 'offer' && (button.style.display = 'none');let stream;try {console.log('尝试调取本地摄像头/麦克风');stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });console.log('摄像头/麦克风获取成功!');localVideo.srcObject = stream;} catch {console.error('摄像头/麦克风获取失败!');return;}console.log(`------ WebRTC ${target === 'offer' ? '发起方' : '接收方'}流程开始 ------`);console.log('将媒体轨道添加到轨道集');stream.getTracks().forEach(track => {peer.addTrack(track, stream);});if (!offerSdp) {console.log('创建本地SDP');const offer = await peer.createOffer();await peer.setLocalDescription(offer);console.log(`传输发起方本地SDP`);socket.send(JSON.stringify(offer));} else {console.log('接收到发送方SDP');await peer.setRemoteDescription(offerSdp);console.log('创建接收方(应答)SDP');const answer = await peer.createAnswer();console.log(`传输接收方(应答)SDP`);socket.send(JSON.stringify(answer));await peer.setLocalDescription(answer);}}</script>
</body>
</html>

在 http_server.php 文件中实现了一个 Web 服务,并根据不同的路由返回对应的 HTML 页面服务,主要是用于提供视频页面的展示。

<?php// 创建一个 HTTP 服务
$http = new Swoole\Http\Server("0.0.0.0", 9501);// 监听客户端请求
$http->on('request', function ($request, $response) {$path = $request->server['request_uri'];switch ($path) {case '/':$html = file_get_contents("index.html");$response->header("Content-Type", "text/html");$response->end($html);break;case '/p2p':$html = file_get_contents("p2p.html");$response->header("Content-Type", "text/html");$response->end($html);break;default:$response->status(404);$response->end("Page Not Found");break;}
});// 启动 HTTP 服务
$http->start();

在 websocket_server.php 文件中实现了一个 WebSocket 服务,并设置了 onOpen、onMessage 和 onClose 回调函数。在 onMessage 回调函数中,遍历所有连接,将消息发送给除当前连接外的其他连接。

<?php// 创建 WebSocket 服务
$server = new Swoole\WebSocket\Server("0.0.0.0", 9502);// 监听 WebSocket 连接事件
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {echo "新的客户端连接: {$request->fd}\n";
});// 监听 WebSocket 消息事件
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {echo "收到消息来自 {$frame->fd}: {$frame->data}, 广播给其他的客户端\n";// 广播给其他的客户端foreach ($server->connections as $fd) {if ($fd != $frame->fd) {$server->push($fd, $frame->data);}}
});// 监听 WebSocket 关闭事件
$server->on('close', function ($ser, $fd) {echo "客户端 {$fd} 关闭连接\n";
});// 启 WebSocket 服务
$server->start();

总结

音视频通信技术方案是基于 WebRTC 实现的,Swoole 在其中的作用是提供了页面的 Web 服务及协调浏览器之间通信的 WebSocket 服务。
WebRTC 是一项重要的技术,它使得实时音视频通信变得简单而高效。通过基于浏览器的 API,WebRTC 可以实现点对点的音视频通信。

这篇关于Swoole 实践篇之结合 WebRTC 实现音视频实时通信方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910765

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影