MediaSoup流媒体之创建Router和WebRtc的创建生产者底层源码分析
MediaSoup流媒体之创建Router和创建WebRtc生产者底层源码分析
前言
WebRTC 从mediasoup流媒体服务器入手, 会看问题全面一些 。 代码简单易学习
这个是请求关键帧? fir、pli
提示:以下是本篇文章正文内容,下面案例可供参考
一、 MediaSoup流媒体底层C++的结构
1、 MediaSoup 中Worker、Router、Transport之间的关系
每个进程有一个Worker管理 房间(Router)
在房间下面每个生产者和消费者的传输transport (PlainTransport, WebRtcTransport 主要这个两个 )
房间管理每个传输的通道Transport
然后这边C++与js之间通信的C++处理的流程
先在Work找处理方法如果没有找到就到Router类中处理方法去找到方法
伪代码
class Worker
{
.....
public:
void OnChannelRequest(...)
{
switch (request->methodId)
{
case: 1;
{
.....
}
....
// 没有找到方法就到Router类中去找到方法
default:
{
....
router->HandleRequest(request);
}
}
}
....
}
class Router
{
.....
public:
void OnChannelRequest(...)
{
switch (request->methodId)
{
case: 100;
{
.....
}
....
// 没有找到方法就到transport类中去找到方法
default:
{
....
transport->HandleRequest(request);
}
}
}
....
}
2、 Mediasoup 业务流程图
二、 MediaSoup 创建 Router源码分析
就不看 js部分的代码 这边看cpp部分的代码
case Channel::ChannelRequest::MethodId::WORKER_CREATE_ROUTER:
{
std::string routerId;
try
{
SetNewRouterIdFromInternal(request->internal, routerId);
}
catch (const MediaSoupError& error)
{
MS_THROW_ERROR("%s [method:%s]", error.buffer, request->method.c_str());
}
auto* router = new RTC::Router(routerId);
// 插入router到map表中
this->mapRouters[routerId] = router;
MS_DEBUG_DEV("Router created [routerId:%s]", routerId.c_str());
request->Accept();
break;
}
三、 Mediasoup 创建WebRtc传输通道
case Channel::ChannelRequest::MethodId::ROUTER_CREATE_WEBRTC_TRANSPORT:
{
std::string transportId;
// This may throw.
SetNewTransportIdFromInternal(request->internal, transportId);
// This may throw.
auto* webRtcTransport = new RTC::WebRtcTransport(transportId, this, request->data);
// Insert into the map.
this->mapTransports[transportId] = webRtcTransport;
MS_DEBUG_DEV("WebRtcTransport created [transportId:%s]", transportId.c_str());
json data = json::object();
webRtcTransport->FillJson(data);
request->Accept(data);
break;
}
// 在WebRtcTransport 构造方法
bool enableUdp{ true };
auto jsonEnableUdpIt = data.find("enableUdp");
if (jsonEnableUdpIt != data.end())
{
if (!jsonEnableUdpIt->is_boolean())
MS_THROW_TYPE_ERROR("wrong enableUdp (not a boolean)");
enableUdp = jsonEnableUdpIt->get<bool>();
}
bool enableTcp{ false };
auto jsonEnableTcpIt = data.find("enableTcp");
if (jsonEnableTcpIt != data.end())
{
if (!jsonEnableTcpIt->is_boolean())
MS_THROW_TYPE_ERROR("wrong enableTcp (not a boolean)");
enableTcp = jsonEnableTcpIt->get<bool>();
}
bool preferUdp{ false };
auto jsonPreferUdpIt = data.find("preferUdp");
if (jsonPreferUdpIt != data.end())
{
if (!jsonPreferUdpIt->is_boolean())
MS_THROW_TYPE_ERROR("wrong preferUdp (not a boolean)");
preferUdp = jsonPreferUdpIt->get<bool>();
}
bool preferTcp{ false };
auto jsonPreferTcpIt = data.find("preferTcp");
if (jsonPreferTcpIt != data.end())
{
if (!jsonPreferTcpIt->is_boolean())
MS_THROW_TYPE_ERROR("wrong preferTcp (not a boolean)");
preferTcp = jsonPreferTcpIt->get<bool>();
}
auto jsonListenIpsIt = data.find("listenIps");
if (jsonListenIpsIt == data.end())
MS_THROW_TYPE_ERROR("missing listenIps");
else if (!jsonListenIpsIt->is_array())
MS_THROW_TYPE_ERROR("wrong listenIps (not an array)");
else if (jsonListenIpsIt->empty())
MS_THROW_TYPE_ERROR("wrong listenIps (empty array)");
else if (jsonListenIpsIt->size() > 8)
MS_THROW_TYPE_ERROR("wrong listenIps (too many IPs)");
std::vector<ListenIp> listenIps(jsonListenIpsIt->size());
for (size_t i{ 0 }; i < jsonListenIpsIt->size(); ++i)
{
auto& jsonListenIp = (*jsonListenIpsIt)[i];
auto& listenIp = listenIps[i];
if (!jsonListenIp.is_object())
MS_THROW_TYPE_ERROR("wrong listenIp (not an object)");
auto jsonIpIt = jsonListenIp.find("ip");
if (jsonIpIt == jsonListenIp.end())
MS_THROW_TYPE_ERROR("missing listenIp.ip");
else if (!jsonIpIt->is_string())
MS_THROW_TYPE_ERROR("wrong listenIp.ip (not an string");
listenIp.ip.assign(jsonIpIt->get<std::string>());
// This may throw.
Utils::IP::NormalizeIp(listenIp.ip);
auto jsonAnnouncedIpIt = jsonListenIp.find("announcedIp");
if (jsonAnnouncedIpIt != jsonListenIp.end())
{
if (!jsonAnnouncedIpIt->is_string())
MS_THROW_TYPE_ERROR("wrong listenIp.announcedIp (not an string)");
listenIp.announcedIp.assign(jsonAnnouncedIpIt->get<std::string>());
}
}
uint16_t port{ 0 };
auto jsonPortIt = data.find("port");
if (jsonPortIt != data.end())
{
if (!(jsonPortIt->is_number() && Utils::Json::IsPositiveInteger(*jsonPortIt)))
MS_THROW_TYPE_ERROR("wrong port (not a positive number)");
port = jsonPortIt->get<uint16_t>();
}
try
{
uint16_t iceLocalPreferenceDecrement{ 0 };
if (enableUdp && enableTcp)
this->iceCandidates.reserve(2 * jsonListenIpsIt->size());
else
this->iceCandidates.reserve(jsonListenIpsIt->size());
for (auto& listenIp : listenIps)
{
if (enableUdp)
{
// ICE 优先级 就是 从是先开始连接
uint16_t iceLocalPreference =
IceCandidateDefaultLocalPriority - iceLocalPreferenceDecrement;
if (preferUdp)
iceLocalPreference += 1000;
uint32_t icePriority = generateIceCandidatePriority(iceLocalPreference);
// This may throw.
RTC::UdpSocket* udpSocket;
// TODO@chensong 这边port 是使用同一个端口吗???
if (port != 0)
udpSocket = new RTC::UdpSocket(this, listenIp.ip, port);
else
udpSocket = new RTC::UdpSocket(this, listenIp.ip);
this->udpSockets[udpSocket] = listenIp.announcedIp;
if (listenIp.announcedIp.empty())
this->iceCandidates.emplace_back(udpSocket, icePriority);
else
this->iceCandidates.emplace_back(udpSocket, icePriority, listenIp.announcedIp);
}
if (enableTcp)
{
uint16_t iceLocalPreference =
IceCandidateDefaultLocalPriority - iceLocalPreferenceDecrement;
if (preferTcp)
iceLocalPreference += 1000;
uint32_t icePriority = generateIceCandidatePriority(iceLocalPreference);
// This may throw.
RTC::TcpServer* tcpServer;
if (port != 0)
tcpServer = new RTC::TcpServer(this, this, listenIp.ip, port);
else
tcpServer = new RTC::TcpServer(this, this, listenIp.ip);
this->tcpServers[tcpServer] = listenIp.announcedIp;
if (listenIp.announcedIp.empty())
this->iceCandidates.emplace_back(tcpServer, icePriority);
else
this->iceCandidates.emplace_back(tcpServer, icePriority, listenIp.announcedIp);
}
// Decrement initial ICE local preference for next IP.
iceLocalPreferenceDecrement += 100;
}
// Create a ICE server. 这边创建ICE 协商 STURN 服务器操作 验证用户合法性
// 1. 验证用户名(16)
// 2. 验证密码 (32)
this->iceServer = new RTC::IceServer(
this, Utils::Crypto::GetRandomString(16), Utils::Crypto::GetRandomString(32));
// Create a DTLS transport.
this->dtlsTransport = new RTC::DtlsTransport(this);