Web即时通信技术——WebRTC

WebRTC(Web Real-Time Communication)是一个开放的项目,旨在在网页端提供实时的音频、视频和数据通信,不需要插件或其他附加软件。它是由Google主导,并在Mozilla、W3C和IETF等组织的支持下开发。WebRTC的目标是使浏览器成为实时通信的强大平台,支持点对点(peer-to-peer)通信。

官方网址:https://webrtc.org/

WebRTC中文网 https://webrtc.org.cn

WebRTC官网 https://webrtc.org/

WebRTC范例 https://webrtc.github.io/samples/

WebRTC特点

实时通信: WebRTC专注于实时通信,包括音频、视频和其他数据。 WebRTC允许从设备中捕获音频和视频流,并在对等连接中传输这些流。WebRTC已经被现代浏览器(如Chrome、Firefox、Safari等)广泛支持,使得开发者能够在Web应用中集成实时通信功能。

点对点通信: WebRTC支持点对点通信,即在两个浏览器之间直接建立连接,而不需要通过中间服务器,不需要插件或其他附加软件。

多媒体引擎: WebRTC包括一个多媒体引擎,用于处理音频和视频流,提供了丰富的API和协议。

NAT穿越和防火墙遍历: WebRTC提供了一些机制,使得在NAT(Network Address Translation)和防火墙等网络设备背后进行通信更为容易。

WebRTC的网络拓扑结构

Mesh 结构

如果两个Client端能够顺利建立P2P 的连接,则直接通过 P2P 互相交换数据;如果由于网络原因,无法打通,则利用 Turn Server 来中转数据。图中的TURN Server 是指支持 TURN 协议的服务器,它扮演着一种网络中继的角色,支持把一个 Client 的数据包透明转发到多个其他的 Client 客户端。同理也可得出一对一的网络模型。

这种完全使用 P2P 方式的网络拓扑结称之为 Mesh 结构。

这种结构的优点在于逻辑简单,容易实现,较为轻量的服务端,TURN 服务器比较简单,一定比例的P2P 成功率可极大减轻服务端的压力。

缺点在于每新增一个客户端,所有的客户端都需要新增一路数据上行,客户端上行带宽占用太大。因此,通话人数越多,效果越差。

SFU通话模型

SFU 的全称是:Selective Forwarding Unit,它是一种通过服务器路由和转发 WebRTC 客户端音视频数据流的方法。

SFU 服务器将自己伪装成了一个WebRTC 的 Peer 客户端,WebRTC 的其他客户端其实并不知道自己通过 P2P 连接过去的是一台真实的客户端还是一台服务器,我们通常把这种连接称之为 P2S,即Peer to Server。

SFU服务器和TURN服务器的不同在于:

TURN 服务器仅仅是提供的一种辅助的数据转发通道,在P2P不通的时候进行透明的数据转发。而 SFU 是和客户端有业务交互的,两者是平等的关系,甚至是可以对WebRTC 客户端的数据转发的申请和控制。

MCU通话网络模型

MCU 的全称是:Multipoint Control Unit,又被称为混合,是实现多方WebRTC交流的另一种策略。

它的主要原理是由 MCU Server 将各路客户端上行的数据流合成为一路,再转发给其他客户端。这种模型相比于 SFU 降低了多人视频通话场景下客户端的下行带宽压力,但是由于合流需要转码操作,因此对服务器端压力比较大,且下发给客户端是固定的合流画面,灵活性不好。

WebRTC 实现服务端和客户端交互的代码

在 Linux 环境下使用 WebRTC 实现服务端和客户端交互的代码一般较为复杂,需要使用信令服务器进行 SDP 交换,并处理 ICE 候选等操作。下面例子是一个简化的代码,使用 WebSocket 作为信令服务器。

创建信令服务器

c 复制代码
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <webrtc/api/peerconnectioninterface.h>

class WebSocketServer {
public:
    WebSocketServer() {
        server_.init_asio();
        server_.set_message_handler(bind(&WebSocketServer::OnMessage, this, ::_1, ::_2));
        server_.set_open_handler(bind(&WebSocketServer::OnOpen, this, ::_1));
        server_.set_close_handler(bind(&WebSocketServer::OnClose, this, ::_1));
    }

    void Run(uint16_t port) {
        server_.listen(port);
        server_.start_accept();
        server_.run();
    }

private:
    void OnMessage(websocketpp::connection_hdl hdl, websocketpp::server<websocketpp::config::asio>::message_ptr msg) {
        std::string message = msg->get_payload();
        // Handle incoming message (Signaling, SDP exchange, etc.)
        // Example: Forward the message to the appropriate WebRTC peer connection
    }

    void OnOpen(websocketpp::connection_hdl hdl) {
        // Handle new WebSocket connection
    }

    void OnClose(websocketpp::connection_hdl hdl) {
        // Handle WebSocket connection close
    }

    websocketpp::server<websocketpp::config::asio> server_;
};

int main() {
    WebSocketServer ws_server;
    ws_server.Run(9000); // Run WebSocket server on port 9000

    return 0;
}

客户端

c 复制代码
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/client.hpp>
#include <webrtc/api/peerconnectioninterface.h>

class WebSocketClient {
public:
    WebSocketClient() {
        client_.init_asio();
        client_.set_message_handler(bind(&WebSocketClient::OnMessage, this, ::_1, ::_2));
        client_.set_open_handler(bind(&WebSocketClient::OnOpen, this, ::_1));
        client_.set_close_handler(bind(&WebSocketClient::OnClose, this, ::_1));
    }

    void Connect(const std::string& uri) {
        websocketpp::lib::error_code ec;
        client_.get_alog().write(websocketpp::log::alevel::app, "Connecting to " + uri);
        client_.connect(uri, ec);
        if (ec) {
            client_.get_alog().write(websocketpp::log::alevel::app, "Error connecting: " + ec.message());
        }
    }

    void Send(const std::string& message) {
        websocketpp::lib::error_code ec;
        client_.send(hdl_, message, websocketpp::frame::opcode::text, ec);
        if (ec) {
            client_.get_alog().write(websocketpp::log::alevel::app, "Error sending message: " + ec.message());
        }
    }

private:
    void OnMessage(websocketpp::connection_hdl hdl, websocketpp::client<websocketpp::config::asio>::message_ptr msg) {
        std::string message = msg->get_payload();
        // Handle incoming message (Signaling, SDP exchange, etc.)
        // Example: Forward the message to the appropriate WebRTC peer connection
    }

    void OnOpen(websocketpp::connection_hdl hdl) {
        client_.get_alog().write(websocketpp::log::alevel::app, "WebSocket connection opened");
        hdl_ = hdl;
        // Perform necessary setup, e.g., create WebRTC peer connection
    }

    void OnClose(websocketpp::connection_hdl hdl) {
        client_.get_alog().write(websocketpp::log::alevel::app, "WebSocket connection closed");
        // Perform necessary cleanup
    }

    websocketpp::client<websocketpp::config::asio> client_;
    websocketpp::connection_hdl hdl_;
};

int main() {
    WebSocketClient ws_client;
    ws_client.Connect("ws://localhost:9000"); // Connect to WebSocket server on localhost:9000
    ws_client.Send("Hello, WebSocket!"); // Send a message

    // Continue with WebRTC logic, e.g., setting up peer connection, SDP exchange, media stream control, etc.

    return 0;
}
相关推荐
火星技术2 小时前
LLM 智能视频字幕助手,支持生成、断句、优化、翻译、视频合成全流程
音视频
cuijiecheng201816 小时前
音视频入门基础:RTP专题(1)——RTP官方文档下载
音视频
EasyCVR16 小时前
EasyCVR视频汇聚平台如何配置webrtc播放地址?
音视频·webrtc
大侠后花园18 小时前
Untiy中如何嵌入前端页面,从而播放推流视频?
前端·音视频
浏览器爱好者20 小时前
谷歌浏览器的音视频播放设置与优化
chrome·音视频
EasyNVR20 小时前
视频转码对画质有影响吗?视频融合平台EasyCVR支持哪些转码格式?
人工智能·音视频
番茄老夫子1 天前
基于python Numpy的24位音频数据读取实例解析
音视频
番茄老夫子1 天前
python 生成24bit音频数据实例解析
开发语言·python·音视频
cuijiecheng20181 天前
音视频入门基础:MPEG2-PS专题(7)——通过FFprobe显示PS流每个packet的信息
音视频
wu_qz1 天前
webrtc之rtc::ArrayView<const uint8_t>
webrtc