【zlm】 webrtc源码讲解

目录

前端WEB

服务器收到请求

服务端的处理

 播放

拉流

参考文章


前端WEB

服务器收到请求

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

HttpSession::onRecvHeaderHttpSession::Handle_Req_POSTHttpSession::Handle_Req_POSTif (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接口安装函数
installWebApiaddHttpListener();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::getAnswerSdpauto 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) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/108867.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java反射机制简单入门

标题 反射能干嘛获取Class对象的三种方式下面开始重点&#xff0c;需要掌握获取类的构造器并进行操作获取成员变量获取成员方法 这块建议先听第一个视频入门&#xff0c;第二个视频深入了解 视频学习地址1 视频学习地址1 正射:知道某个类&#xff0c;类的地址&#xff0c;通过…

水一下文章

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

云服务器下如何部署Django项目详细操作步骤

前期本人完成了“编写你的第一个 Django 应用程序”&#xff0c;有了一个简单的项目代码&#xff0c;在本地window系统自测没问题了&#xff0c;接下来就想办法部署到服务器上&#xff0c;可以通过公网访问我们的Django项目。将开发机器上运行的开发版软件实际安装到服务器上进…

华三路由交换技术基础——计算机网络基础

计算机网络&#xff1a; 定义&#xff1a;一组具有自治权的计算机互联的集合 作用&#xff1a; 1.共享信息资源 2.分解式处理信息 4.负载均衡 5.综合信息服务 它是计算机技术与通信技术的两个领域的结合 一&#xff0c;计算机网络中的基本概念&#xff1a; 局域网&#xff…

springboot MongoDB 主从 多数据源

上一篇&#xff0c;我写了关于用一个map管理mongodb多个数据源&#xff08;每个数据源&#xff0c;只有单例&#xff09;的内容。 springboot mongodb 配置多数据源 临到部署到阿里云的测试环境&#xff0c;发现还需要考虑一下主从的问题&#xff0c;阿里云买的数据库&#x…

ChatGPT 和 Elasticsearch:APM 工具、性能和成本分析

作者&#xff1a;LUCA WINTERGERST 在本博客中&#xff0c;我们将测试一个使用 OpenAI 的 Python 应用程序并分析其性能以及运行该应用程序的成本。 使用从应用程序收集的数据&#xff0c;我们还将展示如何将 LLMs 成到你的应用程序中。 在之前的博客文章中&#xff0c;我们构建…

DOM渲染与优化 - CSS、JS、DOM解析和渲染阻塞问题

文章目录 DOM渲染面试题DOM的渲染过程DOM渲染的时机与渲染进程的概述浏览器的渲染流程1. 解析HTML生成DOM树&#xff1a;遇到<img>标签加载图片2. 解析CSS生成CSSOM(CSS Object Model): 遇见背景图片链接不加载3. 将DOM树和CSSOM树合并生成渲染树&#xff1a;加载可视节点…

windows mysql8.0主从配置

windows mysql8.0主从配置 一、安装两个MySQL并配置 1. 主库配置my.ini&#xff0c;我的主库是安装版 [mysqld] # 设置mysql的安装目录 basedirD:\\soft\\mysql-5.7.39 # 设置mysql数据库的存放目录 datadirD:\\soft\\mysql-5.7.39\\data #设置3306端口 port3306 #主服务器…

SAP ABAP基础知识 访问外部数据库-开发篇

前言 本文主要介绍通过ABAP语言访问外部数据库的几种方式 一、外部数据库配置 本文示例中的代码访问了两个外部数据库 MTD : 外部oracle数据库,其中示例表 ZTTEMP 字段( ZZTNO,WERKS) S4Q : 外部HANA数据库(开发系统访问测试系统的数据库), 使用表USR02,ZTTEMP 二、ABAP访问…

HBS 家庭总线驱动和接收芯片MS1192,应用于电话及相关设备、空调设备、安全设备、AV 装置

MS1192 是适用于 HBS 总线规范&#xff08;日本电子工业协会&#xff09; 的适配器芯片&#xff0c;具备发送、接收数据的功能。在发送接收 单元中&#xff0c;采用 AMI 编码方式&#xff0c;可使用双绞线进行互联&#xff0c;信 号传输采用差分方式。 芯片采用单电源…

MFC-GetAdaptersAddresses获取网卡信息

需要:#pragma comment(lib, "IPHLPAPI.lib") GetAdaptersAddresses函数参数说明 ULONG bufferSize = 0;ULONG result = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize);/*参数1:ULONG Family 网络协议族,此参…

CG MAGIC分享3ds Max卡顿未保存处理方法有哪些?

3ds Max进行建模、渲染这一系列过程中&#xff0c;大家使用中都会遇到各种原因导致软件卡顿或崩溃是很常见的情况。 可以说卡机没关系&#xff0c;可是卡顿发生时&#xff0c;如果之前的工作没有及时保存&#xff0c;可能会导致数据的丢失和时间的浪费。这就是最让人烦躁的了&…