首页 >web前端 >js教程 >WebRTC WHIP 和 WHEP 教程:构建直播应用程序

WebRTC WHIP 和 WHEP 教程:构建直播应用程序

Susan Sarandon
Susan Sarandon原创
2024-11-01 09:38:30214浏览

本文最初发布在计量博客上: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 应用程序,因为他们不需要考虑传统信号方法的复杂细节

WebRTC WHIP & WHEP Tutorial: Build a live Streaming App

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 进行的简化信令降低了与添加信令服务器相关的成本

WebRTC WHIP & WHEP Tutorial: Build a live Streaming App

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 发送信号可以实现更快的连接,从而增强用户体验。

WebRTC WHIP & WHEP Tutorial: Build a live Streaming App

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 加强步骤配置

  1. 安装支持 WHIP 的 GStreamer

  2. 使用 GStreamer 设置 WHIP 服务器

    1. 创建一个 GStreamer 管道来监听 WHIP 连接,如下所示
gst-launch-1.0 whipserversrc name=whip \
  ! queue ! videoconvert ! autovideosink

上述命令启动一个 WHIP 服务器,该服务器接受传入的媒体流并显示它们

  1. 配置服务器以使用Metered.ca TURN 服务器

    1. 修改 GStreamer 管道以使用 TURN 服务器。这很重要,因为 NAT 路由器和防火墙会阻止连接
gst-launch-1.0 whipserversrc name=whip ice-server="turn://YOUR_USERNAME:YOUR_CREDENTIAL@relay.metered.ca:80" \
  ! queue ! videoconvert ! autovideosink
  1. 使用 Node.JS 设置反向代理(可选):

    1. 如果您想管理 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 请求来处理建立连接所需的信令

  1. 捕获媒体流:

    1. 您可以捕获媒体流,例如
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  1. 创建 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",
      },
  ],
});
  1. 将媒体轨道添加到连接:
mediaStream.getTracks().forEach((track) => {
  pc.addTrack(track, mediaStream);
});
  1. 创建 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 服务器服务

WebRTC WHIP & WHEP Tutorial: Build a live Streaming App

使用 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 集成到您的应用程序中。

  1. 初始化 RTCPeerConnection

    1. 使用具有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
  1. 处理传入的媒体轨道

设置事件监听器以从服务器恢复远程轨道

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');
});
  1. 向 WHEP 服务器发送 HTTP GET 请求:

向服务器发送 GET 请求

const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  1. 收到的 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",
      },
  ],
});
  1. 创建并发送 SDP 答案

创建 SDP 应答并通过 HTTP POST 请求将其发送到服务器

mediaStream.getTracks().forEach((track) => {
  pc.addTrack(track, mediaStream);
});
  1. 处理 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 });

在前端处理媒体流

  1. 在 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",
      },
  ],
});
  1. 将远程流附加到视频元素

当触发跟踪事件时,将收到的流附加到视频元素

  1. 处理媒体流事件

    1. 连接状态改变
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;
});
  1. 完整示例代码
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();

WebRTC WHIP & WHEP Tutorial: Build a live Streaming App

计量 TURN 服务器

  1. API: 使用强大的 API 进行 TURN 服务器管理。您可以执行以下操作:通过 API 添加/删除凭据、通过 API 检索每个用户/凭据和用户指标、通过 API 启用/禁用凭据、通过 API 按日期检索使用数据。

  2. 全球地理位置定位:自动将流量定向到最近的服务器,以实现尽可能低的延迟和最高的质量性能。全球任何地方的延迟均低于 50 毫秒

  3. 全球所有地区的服务器:多伦多、迈阿密、旧金山、阿姆斯特丹、伦敦、法兰克福、班加罗尔、新加坡、悉尼、首尔、达拉斯、纽约

  4. 低延迟: 低于 50 毫秒的延迟,在世界任何地方。

  5. 经济高效:即用即付定价,并提供带宽和批量折扣。

  6. 轻松管理: 获取使用日志、帐户达到阈值限制时的电子邮件、账单记录以及电子邮件和电话支持。

  7. 符合标准: 符合基于 UDP、TCP、TLS 和 DTLS 的 RFC 5389、5769、5780、5766、6062、6156、5245、5768、6336、6544、5928。

  8. 多租户: 创建多个凭据并按客户或不同应用分开使用。获取使用日志、计费记录和阈值警报。

  9. 企业可靠性: SLA 正​​常运行时间达 99.999%。

  10. 企业规模: 不限制并发流量或总流量。计量 TURN 服务器提供企业可扩展性

  11. 每月 5 GB 免费: 通过免费计划每月获得 5 GB 免费 TURN 服务器使用量

  12. 在端口 80 和 443 上运行

  13. 支持 TURNS SSL 以允许通过深度数据包检测防火墙进行连接。

  14. 同时支持 TCP 和 UDP

  15. 免费无限制 STUN


您可以考虑我们的其他一些文章:

  1. WebRTC 数据通道:指南

  2. 简单对等教程:为视频、DataChannel 添加 TURN 服务器

  3. 使用计量设置 WebRTC TURN 服务器的指南

  4. WebRTC 与 HLS:哪个最适合您?

以上是WebRTC WHIP 和 WHEP 教程:构建直播应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn