WebRTC WHIP 和 WHEP 教程:构建直播应用程序
本文最初发布在计量博客上:WebRTC WHIP 和 WHEP 教程:构建实时流媒体应用程序
WHIP(WebRTC-HTTP 摄取协议) 和 WHEP(WebRTC-HTTP 出口协议) 是旨在借助标准 HTTP 方法简化 WebRTC 中信号发送的协议
-
WHIP 的定义:WHIP 简化了客户端设备将媒体流发送到服务器的方式。
- 它取代了简单 HTTP GET 请求所需的复杂信号机制,从而更容易将媒体摄取到服务器
WHEP 的定义:WHEP 协议用于将媒体流从服务器传输到客户端。它使用 HTTP 协议来处理媒体消费的信令,从而使客户端设备无需复杂的设置即可接收媒体流
简化 WebRTC 信令的作用
易于实施: WHEP 和 WHIP 使用 HTTP 协议,因此这些协议降低了与
相关的复杂性
无状态通信:这是因为 HTTP 是无状态协议,服务器不需要维护请求之间持续的会话信息。
兼容性提高:由于HTTP具有通用兼容性,因此使用HTTP进行信令是跨平台和设备兼容性的最佳选择
快速开发:开发人员可以更有效地实现 WebRTC 应用程序,因为他们不需要考虑传统信号方法的复杂细节
WHIP 是如何运作的
WHIP 如何处理媒体流摄取
WHIP 协议彻底改变了如何使用 HTTP 信号方法将媒体流从客户端设备发送到服务器
传统上,要设置 WebRTC,您需要使用 Web 套接字或其他协议设置复杂的信号机制。借助 WHIP,通过使用 HTTP 协议发送信号并启动 WebRTC 会话,此过程变得简单
HTTP POST 请求: 此处,客户端设备将正文中包含 SDP 或会话描述协议的 HTTP POST 请求发送到 WHIP 端点
服务器响应: 媒体服务器然后处理 SDP Offer 并使用 200 状态代码进行响应,包括请求正文中的 SDP 答案
ICE 候选交换: WHIP 协议支持 ICE 协议,允许客户端在新的 ICE 候选可用时发送额外的 HTTP PATCH 请求
连接建立: 一旦 SDP 交换完成,就会建立点对点连接,使客户端能够将媒体流式传输到服务器
相对于传统摄入方法的优势
简单性: 通过使用 WHIP 方法,WHIP 减少了对持久连接和信令服务器的需求。
易于实施: 开发者可以使用具有通用兼容性的 HTTP 来加快开发过程
可扩展性:无状态 HTTP 请求允许服务器同时处理多个连接请求,从而轻松管理大量连接。
防火墙和代理友好: HTTP 是防火墙友好的,几乎所有类型的防火墙都允许 HTTP 流量
成本效益: 通过 HTTP 进行的简化信令降低了与添加信令服务器相关的成本
WHEP 是如何运作的
WHEP 协议简化了将媒体从服务器传输到客户端设备的过程。
因此,WHEP 协议使您能够使用 HTTP 来设置从服务器和客户端设备接收媒体的信令。
WHEP 在媒体流中如何工作
HTTP GET 请求: 客户端通过向服务器 WHEP 端点发送 HTTP GET 请求来请求媒体流
SDP Exchange: 服务器在 HTTP 响应中以 SDP Offer 进行响应,然后客户端在后续 POST 请求中发回 SDP 应答
媒体接收: 建立连接后,将通过已建立的 WebRTC 连接接收媒体流。注意:很多时候您需要TURN 服务器来建立 WebRTC 连接
对 ICE 的支持: WHEP 允许通过额外的 HTTP 补丁请求交换 ICE 候选者,从而实现更好的连接
客户端流式传输的优势
简化的客户端实现: 使用 HTTP 请求,从而减少对复杂信号机制的需求
改进的兼容性: 对 HTTP 协议的普遍支持确保了改进的跨设备兼容性
增强的可扩展性: 由于 HTTP 是无状态协议,这提高了服务器的可扩展性,并且使用少量资源即可扩展到大量用户
更好的网络遍历: 因为您可以使用 HTTP 进行信号传输,并且不需要 Web 套接字或其他机制,所以这可以改进连接的 NAT 遍历。建立连接后,您确实需要WebRTC 的 TURN 服务器
减少延迟: 使用 HTTP 发送信号可以实现更快的连接,从而增强用户体验。
WHIP 和 WHEP 之间的协同作用
结合两种协议以实现高效的端到端通信:
通过结合 WHIP 和 WHEP,开发人员可以为 WebRTC 创建全面的信令解决方案
这种组合简化了媒体流的摄取和交付,确保 WebRTC 的实施更加顺利
统一信令方法: 使用 HTTP 进行摄取和交付,创建一致的信令方法
降低复杂性: 开发者只需处理 HTTP 协议,从而减少代码的学习曲线和维护
增强的性能:使用单一信令协议简化代码,可以在传输媒体时缩短连接时间并降低延迟
展示性能改进的用例
直播平台:
交互式应用程序
可扩展架构
构建直播应用程序
在 WebRTC 应用程序中实现 WHIP 和 WHEP 非常简单。在本节中,我们将设置一个 WHIP 服务器并使用节点和 docker 等现代技术将其集成到您的应用程序中
这里我们将使用 Metered.ca TURN 服务器服务进行 NAT 穿越
设置 WHIP 服务器
先决条件和环境设置:
Node.js 和 NPM: 确保您安装了最新的 Node 和 nvm
Metered.ca 帐户: 在 Metered TURN 服务器
上创建免费帐户
公共 IP 地址: 这是可通过互联网访问服务器所必需的。如果您的应用程序使用任何云提供商,您将获得一个免费的公共 IP 地址
WebRTC 媒体服务器: 我们需要一个支持 WHIP 的媒体服务器,例如 GStreamer 或 Janus
使用 Node.Js 和 GStreamer 加强步骤配置
安装支持 WHIP 的 GStreamer
-
使用 GStreamer 设置 WHIP 服务器
- 创建一个 GStreamer 管道来监听 WHIP 连接,如下所示
gst-launch-1.0 whipserversrc name=whip \ ! queue ! videoconvert ! autovideosink
上述命令启动一个 WHIP 服务器,该服务器接受传入的媒体流并显示它们
-
配置服务器以使用Metered.ca TURN 服务器
- 修改 GStreamer 管道以使用 TURN 服务器。这很重要,因为 NAT 路由器和防火墙会阻止连接
gst-launch-1.0 whipserversrc name=whip ice-server="turn://YOUR_USERNAME:YOUR_CREDENTIAL@relay.metered.ca:80" \ ! queue ! videoconvert ! autovideosink
-
使用 Node.JS 设置反向代理(可选):
- 如果您想管理 HTTP 端点或添加任何其他附加逻辑,您可以设置一个简单的 Express js 服务器
const express = require('express'); const httpProxy = require('http-proxy'); const app = express(); const proxy = httpProxy.createProxyServer(); app.post('/whip', (req, res) => { proxy.web(req, res, { target: 'http://localhost:PORT_WHERE_GSTREAMER_IS_RUNNING' }); }); app.listen(3000, () => { console.log('Proxy server running on port 3000'); });
在您的应用程序中实施 WHIP
集成 WHIP 的代码片段:
在客户端,您可以借助 RTCPeerConnection 捕获媒体流,并使用 HTTP 请求来处理建立连接所需的信令
-
捕获媒体流:
- 您可以捕获媒体流,例如
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
- 创建 RTCPeerConnection:
您可以在计量 TURN 服务器的帮助下创建 RTCPeerConnection
var myPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.relay.metered.ca:80", }, { urls: "turn:global.relay.metered.ca:80", username: "your-username", credential: "your-credential", }, { urls: "turn:global.relay.metered.ca:80?transport=tcp", username: "your-username", credential: "your-credential", }, { urls: "turn:global.relay.metered.ca:443", username: "your-username", credential: "your-credential", }, { urls: "turns:global.relay.metered.ca:443?transport=tcp", username: "your-username", credential: "your-credential", }, ], });
- 将媒体轨道添加到连接:
mediaStream.getTracks().forEach((track) => { pc.addTrack(track, mediaStream); });
- 创建 SDP 报价并将其发送到 WHIP 服务器:
const offer = await pc.createOffer(); await pc.setLocalDescription(offer); const response = await fetch('http://YOUR_SERVER_IP:3000/whip', { method: 'POST', headers: { 'Content-Type': 'application/sdp' }, body: pc.localDescription.sdp, }); const sdpAnswer = await response.text(); await pc.setRemoteDescription({ type: 'answer', sdp: sdpAnswer });
处理信令的 HTTP 请求和响应
-
客户端:
-
HTTP POST 请求:
- 网址:http://YOUR_SERVER_IP:3000/whip
- 标头:{ 'Content-Type': 'application/sdp' }
- 正文:纯文本形式的 SDP 报价
-
期待回复:
- 状态:201 已创建
- 标题:带有资源 URL 的位置标题
- 正文:纯文本形式的 SDP 答案
-
-
服务器端:
-
接收 SDP 优惠:
- 从 req.body 中读取 SDP
- 创建WebRTC端点并设置远程描述
-
生成 SDP 答案
- 来自服务器 WebRTC 端点的 SDP 应答
- 将 SDP 答案发送回 res.body
- 使用 Metered.ca TURN 服务器服务
-
使用 Metered.ca TURN 服务器服务
TURN 服务器的用途
当无法进行直接点对点连接时,促进媒体穿越 NAT 和防火墙
将 TURN 服务器合并到 ICE 服务器配置中
这是 TURN 服务器凭证和 ICE 服务器
gst-launch-1.0 whipserversrc name=whip \ ! queue ! videoconvert ! autovideosink
部署 WHEP 客户端
拥有 WHIP 客户端允许您的应用程序使用 HTTP 信号从服务器接收媒体流。
在客户端集成 WHEP
基本了解 Javascript 中的 WebRTC API
支持 WHEP GStreamer Janus 或任何其他
的媒体服务器
Metered.ca TURN 服务器凭据
逐步将 WHEP 集成到您的应用程序中。
-
初始化 RTCPeerConnection
- 使用具有metered.ca转服务器的ICE服务器创建一个RTCPeerConnection实例
gst-launch-1.0 whipserversrc name=whip ice-server="turn://YOUR_USERNAME:YOUR_CREDENTIAL@relay.metered.ca:80" \ ! queue ! videoconvert ! autovideosink
- 处理传入的媒体轨道
设置事件监听器以从服务器恢复远程轨道
const express = require('express'); const httpProxy = require('http-proxy'); const app = express(); const proxy = httpProxy.createProxyServer(); app.post('/whip', (req, res) => { proxy.web(req, res, { target: 'http://localhost:PORT_WHERE_GSTREAMER_IS_RUNNING' }); }); app.listen(3000, () => { console.log('Proxy server running on port 3000'); });
- 向 WHEP 服务器发送 HTTP GET 请求:
向服务器发送 GET 请求
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
- 收到的 SDP 报价的远程描述
var myPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.relay.metered.ca:80", }, { urls: "turn:global.relay.metered.ca:80", username: "your-username", credential: "your-credential", }, { urls: "turn:global.relay.metered.ca:80?transport=tcp", username: "your-username", credential: "your-credential", }, { urls: "turn:global.relay.metered.ca:443", username: "your-username", credential: "your-credential", }, { urls: "turns:global.relay.metered.ca:443?transport=tcp", username: "your-username", credential: "your-credential", }, ], });
- 创建并发送 SDP 答案
创建 SDP 应答并通过 HTTP POST 请求将其发送到服务器
mediaStream.getTracks().forEach((track) => { pc.addTrack(track, mediaStream); });
- 处理 ICE 候选人交换(可选):
如果您需要单独发送 ICE 候选人,请处理icecandidate 事件
const offer = await pc.createOffer(); await pc.setLocalDescription(offer); const response = await fetch('http://YOUR_SERVER_IP:3000/whip', { method: 'POST', headers: { 'Content-Type': 'application/sdp' }, body: pc.localDescription.sdp, }); const sdpAnswer = await response.text(); await pc.setRemoteDescription({ type: 'answer', sdp: sdpAnswer });
在前端处理媒体流
- 在 HTML 中创建视频元素
var myPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.relay.metered.ca:80", }, { urls: "turn:global.relay.metered.ca:80", username: "e13b9bsdfdsfsdfb0676cc5b6", credential: "dedewdewfer+gq5iT", }, { urls: "turn:global.relay.metered.ca:80?transport=tcp", username: "e13bdfdsfds6b0676cc5b6", credential: "dewfrefre+gq5iT", }, { urls: "turn:global.relay.metered.ca:443", username: "e13b9fsdfdsfsd86b0676cc5b6", credential: "csdfwefeer+gq5iT", }, { urls: "turns:global.relay.metered.ca:443?transport=tcp", username: "e13b9dsfsdfe6b0676cc5b6", credential: "sdfewtrererer+gq5iT", }, ], });
- 将远程流附加到视频元素
当触发跟踪事件时,将收到的流附加到视频元素
-
处理媒体流事件
- 连接状态改变
var myPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.relay.metered.ca:80", }, { urls: "turn:global.relay.metered.ca:80", username: "e13b9bsdfdsfsdfb0676cc5b6", credential: "dedewdewfer+gq5iT", }, { urls: "turn:global.relay.metered.ca:80?transport=tcp", username: "e13bdfdsfds6b0676cc5b6", credential: "dewfrefre+gq5iT", }, { urls: "turn:global.relay.metered.ca:443", username: "e13b9fsdfdsfsd86b0676cc5b6", credential: "csdfwefeer+gq5iT", }, { urls: "turns:global.relay.metered.ca:443?transport=tcp", username: "e13b9dsfsdfe6b0676cc5b6", credential: "sdfewtrererer+gq5iT", }, ], });
b.需要协商
pc.addEventListener('track', (event) => { const [remoteStream] = event.streams; // Attach the remote stream to a video element const remoteVideo = document.getElementById('remoteVideo'); remoteVideo.srcObject = remoteStream; });
- 完整示例代码
const whepServerEndpoint = 'http://YOUR_SERVER_IP:3000/whep'; // Replace with your server's WHEP endpoint const response = await fetch(whepEndpoint, { method: 'GET', headers: { Accept: 'application/sdp', }, }); const sdpOffer = await response.text();
计量 TURN 服务器
API: 使用强大的 API 进行 TURN 服务器管理。您可以执行以下操作:通过 API 添加/删除凭据、通过 API 检索每个用户/凭据和用户指标、通过 API 启用/禁用凭据、通过 API 按日期检索使用数据。
全球地理位置定位:自动将流量定向到最近的服务器,以实现尽可能低的延迟和最高的质量性能。全球任何地方的延迟均低于 50 毫秒
全球所有地区的服务器:多伦多、迈阿密、旧金山、阿姆斯特丹、伦敦、法兰克福、班加罗尔、新加坡、悉尼、首尔、达拉斯、纽约
低延迟: 低于 50 毫秒的延迟,在世界任何地方。
经济高效:即用即付定价,并提供带宽和批量折扣。
轻松管理: 获取使用日志、帐户达到阈值限制时的电子邮件、账单记录以及电子邮件和电话支持。
符合标准: 符合基于 UDP、TCP、TLS 和 DTLS 的 RFC 5389、5769、5780、5766、6062、6156、5245、5768、6336、6544、5928。
多租户: 创建多个凭据并按客户或不同应用分开使用。获取使用日志、计费记录和阈值警报。
企业可靠性: SLA 正常运行时间达 99.999%。
企业规模: 不限制并发流量或总流量。计量 TURN 服务器提供企业可扩展性
每月 5 GB 免费: 通过免费计划每月获得 5 GB 免费 TURN 服务器使用量
在端口 80 和 443 上运行
支持 TURNS SSL 以允许通过深度数据包检测防火墙进行连接。
同时支持 TCP 和 UDP
免费无限制 STUN
您可以考虑我们的其他一些文章:
WebRTC 数据通道:指南
简单对等教程:为视频、DataChannel 添加 TURN 服务器
使用计量设置 WebRTC TURN 服务器的指南
WebRTC 与 HLS:哪个最适合您?
以上是WebRTC WHIP 和 WHEP 教程:构建直播应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python和JavaScript开发者的薪资没有绝对的高低,具体取决于技能和行业需求。1.Python在数据科学和机器学习领域可能薪资更高。2.JavaScript在前端和全栈开发中需求大,薪资也可观。3.影响因素包括经验、地理位置、公司规模和特定技能。

实现视差滚动和元素动画效果的探讨本文将探讨如何实现类似资生堂官网(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

如何在JavaScript中将具有相同ID的数组元素合并到一个对象中?在处理数据时,我们常常会遇到需要将具有相同ID�...

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

探索前端中类似VSCode的面板拖拽调整功能的实现在前端开发中,如何实现类似于VSCode...
