----------------------------------------------------------------------------------------------------------------------------------------
一分钟快速搭建 rtmpd 服务器: https://blog.csdn.net/freeabc/article/details/102880984
软件下载地址: http://www.qiyicc.com/download/rtmpd.rar
github 地址:https://github.com/superconvert/smart_rtmpd
-----------------------------------------------------------------------------------------------------------------------------------------

webrtc 中有关 socket 运行机制以及 stun 收发过程 及 Candidates 生成流程分析
我写文章一般是两个思路:
1. 下一步要调用什么对象的方法
2. 这一步的对象,怎么关联到下一步的对象的流程分析
这一步的流程主要阐述怎么关联下一步的对象的流程分析,当然这一步做了什么具体的工作,不能
详细展示,否则,太庞大了,需要各位朋友针对重点的部分,自己揣摩了。
//*******************************************************************************************
//
// webrtc 内部很多创建 socket 的地方,这个需要调用类厂 BasicPacketSocketFactory , 下面
// 这一小段就是分析 BasicPacketSocketFactory 的创建,以及内部管理的 socket 的部分流程
//
//*******************************************************************************************
AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
const SocketAddress& address,
uint16_t min_port,
uint16_t max_port) {
// 参见下面的 SocketDispatcher
AsyncSocket* socket =
socket_factory()->CreateAsyncSocket(address.family(), SOCK_DGRAM);
if (!socket) {
return NULL;
}
// 这个 BindSocket 最终会调用系统的 bind
if (BindSocket(socket, address, min_port, max_port) < 0) {
RTC_LOG(LS_ERROR) << "UDP bind failed with error " << socket->GetError();
delete socket;
return NULL;
}
// 这个里面绑定了读和写事件到 AsyncUDPSocket::OnReadEvent , AsyncUDPSocket::OnWriteEvent
return new AsyncUDPSocket(socket);
}
1. 创建 BasicPacketSocketFactory
./pc/peer_connection_factory.cc
BasicPacketSocketFactory 是 PeerConnectionFactory::Initialize() 中创建的
default_socket_factory_.reset(new rtc::BasicPacketSocketFactory(network_thread_));
2.
./sdk/android/src/jni/pc/peer_connection_factory.cc
而 network_thread_ 则是 接口 CreatePeerConnectionFactoryForJava 里的
std::unique_ptr<rtc::Thread> network_thread = rtc::Thread::CreateWithSocketServer();
其实就是这个
std::unique_ptr<Thread> Thread::CreateWithSocketServer() {
return std::unique_ptr<Thread>(new Thread(SocketServer::CreateDefault()));
}
其实就是创建了 PhysicalSocketServer
std::unique_ptr<SocketServer> SocketServer::CreateDefault() {
#if defined(__native_client__)
return std::unique_ptr<SocketServer>(new rtc::NullSocketServer);
#else
return std::unique_ptr<SocketServer>(new rtc::PhysicalSocketServer);
#endif
}
Thread 继承于 class Thread : public MessageQueue, public webrtc::TaskQueueBase ,我们看出 Thread 拥有消息队列的对象
构造函数 Thread(SocketServer* ss)把 ss 赋值给基类 MessageQueue,基类接口通过 socketserver 返回这个对象,后续只要
调用接口 socketserver 的,就是返回这个 socket 对象。
SocketServer* MessageQueue::socketserver() {
return ss_;
}
上面的 BasicPacketSocketFactory::CreateUdpSocket 里的,这句话 socket_factory()->CreateAsyncSocket 其实就是调用
./rtc_base/physical_socket_server.cc
AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int family, int type) {
SocketDispatcher* dispatcher = new SocketDispatcher(this);
// 这个里面通过 PhysicalSocket::Create 创建一个套接字
if (dispatcher->Create(family, type)) {
return dispatcher;
} else {
delete dispatcher;
return nullptr;
}
}
//******************************************************************************
//
// 下面这段是讲述 socket 怎么接收数据的,和上述流程没任何关系
//
//******************************************************************************
上述流程中,有一个这个函数调用,
std::unique_ptr<Thread> Thread::CreateWithSocketServer() {
return std::unique_ptr<Thread>(new Thread(SocketServer::CreateDefault()));
}
创建一个带线程的 socket 这个线程的 Run 如下:
void Thread::Run() {
ProcessMessages(kForever);
}
// 这个里面不断的 Get 最新的 message 进行处理
bool Thread::ProcessMessages(int cmsLoop) {
// Using ProcessMessages with a custom clock for testing and a time greater
// than 0 doesn't work, since it's not guaranteed to advance the custom
// clock's time, and may get stuck in an infinite loop.
RTC_DCHECK(GetClockForTesting() == nullptr || cmsLoop == 0 ||
cmsLoop == kForever);
int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
int cmsNext = cmsLoop;
while (true) {
#if defined(WEBRTC_MAC)
ScopedAutoReleasePool pool;
#endif
Message msg;
if (!Get(&msg, cmsNext))
return !IsQuitting();
Dispatch(&msg);
if (cmsLoop != kForever) {
cmsNext = static_cast<int>(TimeUntil(msEnd));
if (cmsNext < 0)
return true;
}
}
}
// 其实就是基类的 MessageQueue 的接口
bool MessageQueue::Get(Message* pmsg, int cmsWait, bool process_io)
// 看到这个 ss_ 了吗,就是 SocketServer::CreateDefault() 也就是 PhysicalSocketServer::Wait 接口
if (!ss_->Wait(static_cast<int>(cmsNext), process_io))
这个地方监听所有的 socket 操作,三个版本的都有 win, linux,随便找一个分析
./rtc_base/physical_socket_server.cc
bool PhysicalSocketServer::Wait(int cmsWait, bool process_io)
return WaitEpoll(cmsWait, signal_wakeup_);
bool PhysicalSocketServer::WaitEpoll(int cmsWait)
ProcessEvents(pdispatcher, readable, writable, check_error);
static void ProcessEvents(Dispatcher* dispatcher, bool readable, bool writable, bool check_error)
// 这里就是 SocketDispatcher -
dispatcher->OnEvent(ff, errcode);
void SocketDispatcher::OnEvent(uint32_t ff, int err)
// 如果是读,这里假设是 UDP
SignalReadEvent(this);
./rtc_base/async_udp_socket.cc
void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket)
SignalReadPacket(this, buf_, static_cast<size_t>(len), remote_addr,
(timestamp > -1 ? timestamp : TimeMicros()));
./p2p/base/stun_port.cc
void UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us) {
RTC_DCHECK(socket == socket_);
RTC_DCHECK(!remote_addr.IsUnresolvedIP());
// Look for a response from the STUN server.
// Even if the response doesn't match one of our outstanding requests, we
// will eat it because it might be a response to a retransmitted packet, and
// we already cleared the request when we got the first response.
if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
// 这是 stun 阶段接收包
requests_.CheckResponse(data, size);
return;
}
// 这是建立链接后接收包,参考 webrtc 的视频数据接收过程
if (Connection* conn = GetConnection(remote_addr)) {
conn->OnReadPacket(data, size, packet_time_us);
} else {
Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
}
}
//******************************************************************************
//
// 下面就分析了有关 webrtc stun 流程的部分
//
//******************************************************************************
1. 从这里开始分析,这个的调用参考 createPeerConnection 流程
JsepTransportController::MaybeStartGathering
2. 这个 ice_transport 就是 P2PTransportChannel 对象
dtls->ice_transport()->MaybeStartGathering();
3. 第一次创建流程
./p2p/base/p2p_transport_channel.cc
P2PTransportChannel::MaybeStartGathering
//------------------------------------------------------------
// 这个就是创建一个 PortAllocatorSession 并把信号挂接 P2PTransportChannel
//------------------------------------------------------------
AddAllocatorSession(allocator_->CreateSession(
transport_name(),

本文深入分析了WebRTC中的STUN机制,包括socket运行机制、STUN收发过程及Candidates生成流程。同时,介绍了如何在一分钟内快速搭建RTMP服务器,提供了软件下载地址和GitHub项目链接。
82

被折叠的 条评论
为什么被折叠?



