【zlm】 webrtc源码讲解

目录

前端WEB

服务器收到请求

服务端的处理

播放

拉流

参考文章


前端WEB

服务器收到请求

POST /index/api/webrtc?app=live&stream=test&type=play HTTP/1.1

HttpSession::onRecvHeader
  HttpSession::Handle_Req_POST
   

HttpSession::Handle_Req_POST
  if (totalContentLen > 0 && (size_t)totalContentLen < maxReqSize )
    _contentCallBack = [this,parserCopy](const char *data,size_t len) {
            //恢复http头
            _parser = parserCopy;
            //设置content
            _parser.setContent(string(data,len));
            //触发http事件,emitHttpEvent内部会选择是否关闭连接
            emitHttpEvent(true);
            //清空数据,节省内存
            _parser.Clear();
            //content已经接收完毕
            return false;
        };


HttpSession::onRecvContent(const char *data,size_t len)
  if (_contentCallBack)
    _contentCallBack(data,len);        


HttpSession::emitHttpEvent
  // 广播HTTP事件
  NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,
                                     consumed,static_cast<SockInfo &>(*this));

服务端的处理

// 主函数中调用web接口安装函数
installWebApi
  addHttpListener();
  api_regist("/index/api/webrtc",[](API_ARGS_STRING_ASYNC){
    auto type = allArgs["type"];
    auto offer = allArgs.getArgs();
    WebRtcPluginManager::Instance().getAnswerSdp(*(static_cast<Session *>(&sender)), type,
                                                   WebRtcArgsImp(allArgs, sender.getIdentifier()),
                                                   [invoker, val, offer, headerOut](const WebRtcInterface &exchanger) mutable {
            headerOut["Content-Type"] = HttpFileManager::getContentType(".json");
            headerOut["Access-Control-Allow-Origin"] = "*";
            val["sdp"] = const_cast<WebRtcInterface &>(exchanger).getAnswerSdp(offer);
            val["id"] = exchanger.getIdentifier();
            val["type"] = "answer";
            invoker(200, headerOut, val.toStyledString());
        });
    });


addHttpListener
   //注册监听kBroadcastHttpRequest事件
    NoticeCenter::Instance().addListener(&web_api_tag, Broadcast::kBroadcastHttpRequest,
                                         [](BroadcastHttpRequestArgs) {
      auto it = s_map_api.find(parser.Url());
      it->second(parser, invoker, sender);
	}                  

根据url找到对应的事件回调,最终会调用WebRtcPluginManager::Instance().getAnswerSdp。

WebRtcPluginManager::getAnswerSdp
  auto it = _map_creator.find(type);
  it->second(sender, args, cb);
  

// 静态注册插件
WebRtcPluginManager::Instance().registerPlugin("play", play_plugin);


void play_plugin(Session &sender, const WebRtcArgs &args, const WebRtcPluginManager::onCreateRtc &cb)
  // 使用rtsp媒体源,两者均是传输的rtp流
  info._schema = RTSP_SCHEMA;
  MediaSource::findAsync(info, session_ptr, [=](const MediaSource::Ptr &src_in) mutable {
    auto src = dynamic_pointer_cast<RtspMediaSource>(src_in);
    // 还原成rtc,目的是为了hook时识别哪种播放协议
    info._schema = RTC_SCHEMA;
    auto rtc = WebRtcPlayer::create(EventPollerPool::Instance().getPoller(), src, info, preferred_tcp);
      cb(*rtc); // 发送answer SDP给web端
    });    

播放

拉流


Web端首先根据协商的IP和端口,服务端webrtc的端口是8000,发送STUN命令再次获取STUN地址。

首次连接,服务端会创建对应的session。

WebRtcSession::WebRtcSession(const Socket::Ptr &sock) : Session(sock)

socklen_t addr_len = sizeof(_peer_addr);

getpeername(sock->rawFD(), (struct sockaddr *)&_peer_addr, &addr_len);

WebRtcSession::onRecv_l(const char *data, size_t len)

// 首次进入,根据username获取之前创建的transport.

auto user_name = getUserName(data, len); // 此处的username就是之前设置的transport标识

auto transport = WebRtcTransportManager::Instance().getItem(user_name);

transport->setSession(shared_from_this());

_transport = std::move(transport);

_transport->inputSockData((char *)data, len, (struct sockaddr *)&_peer_addr);

WebRtcTransport::inputSockData

// 处理STUN消息

if (RTC::StunPacket::IsStun((const uint8_t *)buf, len))

std::unique_ptr<RTC::StunPacket> packet(RTC::StunPacket::Parse((const uint8_t *)buf, len));

_ice_server->ProcessStunPacket(packet.get(), tuple);

return;

// 处理

if (is_dtls(buf))

_dtls_transport->ProcessDtlsData((uint8_t *)buf, len);

return;

// 由于是拉流,不存在rtp数据,但是有rtcp数据

if (is_rtcp(buf))

if (_srtp_session_recv->DecryptSrtcp((uint8_t *)buf, &len))

onRtcp(buf, len);

DTLS交互完成后,接下来启动媒体传输

WebRtcTransport::OnDtlsTransportConnected

onStartWebRTC();

WebRtcPlayer::onStartWebRTC

WebRtcTransportImp::onStartWebRTC();

_reader = _play_src->getRing()->attach(getPoller(), true);

weak_ptr<WebRtcPlayer> weak_self = static_pointer_cast<WebRtcPlayer>(shared_from_this());

weak_ptr<Session> weak_session = getSession();

_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) {

size_t i = 0;

pkt->for_each([&](const RtpPacket::Ptr &rtp) {

strong_self->onSendRtp(rtp, ++i == pkt->size());

});

});

参考文章

zlm源码研究 - webrtc播放-CSDN博客

WebRTC: Real-Time Communication in Browsers (w3.org)

相关推荐
Black蜡笔小新35 分钟前
WebRTC嵌入式视频通话SDK:EasyRTC从免插件到轻量级带来的音视频通话技术
音视频·webrtc·sdk·rtc·webp2p
EasyNVR37 分钟前
EasyRTC:开启智能硬件与全平台互动新时代
网络·音视频·webrtc·p2p·智能硬件·视频监控
EasyGBS38 分钟前
从开发到部署:EasyRTC嵌入式视频通话SDK如何简化实时音视频通信的集成与应用
音视频·webrtc·实时音视频·视频监控
EasyNVR13 小时前
智能硬件新时代,EasyRTC开启物联音视频新纪元
运维·服务器·音视频·webrtc·p2p·智能硬件·视频监控
科技小E15 小时前
EasyRTC:智能硬件适配,实现多端音视频互动新突破
网络协议·安全·小程序·音视频·webrtc·p2p·视频监控
EasyNVR3 天前
EasyRTC智能硬件:小体积,大能量,开启音视频互动新体验
前端·安全·音视频·webrtc·sdk·p2p·智能硬件
科技小E4 天前
WebRTC与EasyRTC:开启智能硬件音视频通讯的全新旅程
网络·网络协议·音视频·webrtc·p2p·视频监控
cyw89984 天前
vue3读取webrtc-stream 视频流
webrtc
Likeadust5 天前
WebP2P+自研回音消除:视频通话SDK嵌入式EasyRTC构建高交互性音视频应用
音视频·webrtc·p2p·webp2p
EasyGBS6 天前
EasyRTC嵌入式WebRTC视频通话SDK支持Web浏览器、Linux、ARM、Android、iOS
arm开发·音视频·webrtc·webp2p