做cloudmeeting项目已经有一段时间了,目前已经支持了RTMP的部分,但是在支持WebRTC上面遇到了一些困难,于是记录libdatachannel库的使用方法,API以及主要架构

架构

首先,这是一个相较于libwebrtc更加精简的native库在安装过程中有三个部件,ws(websocket)、srtp、core。在安装的时候推荐使用mvsc编译器版本的,即使用vcpkg直接安装(或者其他的包管理器。另外MIngw版本我尝试了很多的方法,诸如conan管理器,Msys2,甚至分部件编译,都无法正常工作。主要是卡在srtp部件中的libsrtp和openssl上面。综上推荐直接使用mvsc版本,即x64-windows(vcpkg)

这个库实现了这样几件事情,用于音频/视频流的 WebRTC 媒体传输(可选)、用于客户端-服务器通信的 WebSocket 协议(可选)。并且提供C++和C两套API,可编译成Wasm。这实际上就提供了很强的扩展性,无论是iWindows程序还是网页程序都是可以无缝迁移的。

一个最小实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "rtc/rtc.hpp"
/// 初始化
rtc::configuration config;
config.iceServers.emplace_back("stun:stun.l.google.com:19302");
rtc::PeerConnection pc(config);

///设置回调
pc.onLocalDescription([](rtc::Description sdp) {
// Send the SDP to the remote peer through your signaling server
sendToSignalingServer(std::string(sdp));
});

pc.onLocalCandidate([](rtc::Candidate candidate) {
// Send the candidate to the remote peer
sendToSignalingServer(candidate.candidate(), candidate.mid());
});


/// 创建数据通道
auto dc = pc.createDataChannel("test");

dc->onOpen([]() {
std::cout << "Data channel open" << std::endl;
});

dc->onMessage([](std::variant<rtc::binary, rtc::string> message) {
if (std::holds_alternative<rtc::string>(message)) {
std::cout << "Received: " << std::get<rtc::string>(message) << std::endl;
}
});

/// 处理接收信息
void onRemoteDescriptionReceived(std::string sdp) {
pc.setRemoteDescription(rtc::Description(sdp));
}
void onRemoteCandidateReceived(std::string candidate, std::string mid) {
pc.addRemoteCandidate(rtc::Candidate(candidate, mid));
}

另外在dc库的代码中使用的设计模式叫做pimpl(pointer to Implementation)。实际上就是通过一个私有的成员指针,将指针指向的类的内部实现全部隐藏。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
///  .h文件
class PAimpl;

class A
{
public:
A()
{
// initial work
}
~A() {
// free resource
}
public:
void func1(int a, char* b);
bool isEnabled();
// other public interface which will exposed outside
private:
PAimpl* pimpl;
};

/// .cpp文件
class PAimpl
{
public:
void func1(int a, char* b)
{
// implementation
}
bool isEnabled()
{
// implementation
return true;
}
};

void A::func1(int a, char* b)
{
pimpl->func1(a, b);
}

bool A::isEnabled()
{
return pimpl->isEnabled();
}



SDP创建

在dc中创建SDP分为两种情况,第一种是仅Datachannel的SDP和第二种传输Track的SDP

第一种不需要传入编码器等参数,SDP会自动生成基本会话信息和SCTP应用层描述。生成SDP包括

1
2
3
4
会话级别信息(v=, o=, s=, t=) 
ICE 参数(ice-ufrag, ice-pwd, ice-options)
DTLS 指纹(fingerprint)
SCTP 端口和最大消息大小

第二种需要传递音视频编码器参数,在我的项目中需要与SRS服务器链接,那么需要添加的参数还要更多。

1
2
3
4
5
6
7
8
9
// 创建音频轨道  
auto audio = std::make_shared<rtc::Description::Audio>("audio");
audio->addOpusCodec(111); // 使用默认 profile

// 创建视频轨道
auto video = std::make_shared<rtc::Description::Video>("video");
video->addH264Codec(96); // 使用默认 profile
// 或自定义 profile
video->addH264Codec(96, "profile-level-id=42e01f;packetization-mode=1");

datachannel创建


本站由 Edison.Chen 创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

undefined