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;
}
相关推荐
浮华落定7 小时前
DeepSeek+即梦 做AI视频
人工智能·chatgpt·音视频
Black蜡笔小新12 小时前
从中心化到点对点:视频通话SDK组件EasyRTC如何通过WebP2P技术实现低延迟通信
网络协议·音视频·p2p
清月电子17 小时前
BT401双模音频蓝牙模块如何开启ble的透传,有什么注意事项
单片机·嵌入式硬件·物联网·音视频
深圳市青牛科技实业有限公司17 小时前
芯麦 GC1808:高性能、低成本的立体声音频模数转换器
人工智能·嵌入式硬件·算法·音视频·能源·新能源·电动工具
cuijiecheng201817 小时前
音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现
ffmpeg·音视频
京河小蚁18 小时前
微信云开发小程序音频播放踩坑记录 - 从熄屏播放到iOS静音
微信·小程序·音视频
9527华安18 小时前
FPGA实现SDI视频解码转GTY光口传输,基于GS2971+Aurora 8b/10b编解码架构,提供工程源码和技术支持
fpga开发·架构·音视频·8b/10b·sdi·gty·gs2971
shawn·xiao18 小时前
Android:播放Rtsp视频流的两种方式
android·音视频·视频
忘不了情20 小时前
前端如何播放二进制音频数据
javascript·react.js·音视频
lucky-billy1 天前
Qt 中使用 ffmpeg 获取采集卡数据录制视频
qt·ffmpeg·音视频