licode 源码分析(四) pipeline

本文深入探讨licode源码中的pipeline结构,分析了相关类的介绍,特别是pipeline如何进行read操作。首先介绍了pipeline内部是一个包含不同类型PipelineContext的vector,如IN、OUT和BOTH。接着详细阐述了pipeline的read过程,通过addFront()添加handler,并在finalize()中建立handler间的连接。最后,以InboundContextImpl<Handler>为例,展示了read函数如何通过fireRead()触发链式处理,形成一个处理链路。
摘要由CSDN通过智能技术生成

一、相关类介绍

licode中的pipeline 内部是一个保存PipelineContext的vector,有IN(输入)、OUT(输出)、BOTH(输入输出)三种类型。

 std::vector<PipelineContext*> inCtxs_;
 std::vector<PipelineContext*> outCtxs_;
 Both 类型对应ContextImpl

 

 pipeline中的类基本都是模板类,下面看下怎么添加到vector中的:

template <class H>
PipelineBase& PipelineBase::addFront(std::shared_ptr<H> handler) {
  typedef typename ContextType<H>::type Context;
  return addHelper(
      std::make_shared<Context>(shared_from_this(), std::move(handler)),
      true);
}

addFront的参数是流处理的一些handler,比如RtcpProcessorHandler、FecReceiverHandler等,这些handler和PipeLineBase作为参数生成Context,vector中保存的其实是Context。分析下Context具体是什么。

//是个结构体模板,这个语法比较难度,下面把它展开
template <class Handler>
struct ContextType {
  typedef typename std::conditional<
    Handler::dir == HandlerDir::BOTH,
    ContextImpl<Handler>,
    typename std::conditional<
      Handler::dir == HandlerDir::IN,
      InboundContextImpl<Handler>,
      OutboundContextImpl<Handler>
    >::type>::type
  type;
};
//展开这个模板,相当于下面的语法
if(Handler::dir == HandlerDir::BOTH)
{
  type  = ContextImpl<Handler>;
}
else if (Handler::dir == HandlerDir::IN)
{
   type = InboundContextImpl<Handler> ;
}
else
  type = OutboundContextImpl<Handler>;

所以ContextType根据参数Handler的不同类型,其type分别对应
ContextImpl<Handler>、 InboundContextImpl<Handler> 、OutboundContextImpl<Handler>
这三个模板类都继承自PipelineContext,对应文章开头说的pipeline其实就是保存pipeline的vector

二、pipeline 是怎么read的

        pipeline在addFront()添加完Handler后,会调用pipeline_->finalize();

      每个PipeContext都有nextIn_和nextOut_两个变量,finalize会遍历vector,每个PipeConext的nextIn_会指向vector中下一个PipeContext,相当于把vector中的所有Handler组成一个“链表”联系起来,其中front_是IN的头,back_是OUT的头。代码如下:

void Pipeline::finalize() {
  front_ = nullptr;
  if (!inCtxs_.empty()) {
    front_ = dynamic_cast<InboundLink*>(inCtxs_.front());
    for (size_t i = 0; i < inCtxs_.size() - 1; i++) {
      inCtxs_[i]->setNextIn(inCtxs_[i+1]);
    }
    inCtxs_.back()->setNextIn(nullptr);
  }

  back_ = nullptr;
  if (!outCtxs_.empty()) {
    back_ = dynamic_cast<OutboundLink*>(outCtxs_.back());
    for (size_t i = outCtxs_.size() - 1; i > 0; i--) {
      outCtxs_[i]->setNextOut(outCtxs_[i-1]);
    }
    outCtxs_.front()->setNextOut(nullptr);
  }

  if (!front_) {
    
  if (!back_) {
    
  }

  for (auto it = ctxs_.rbegin(); it != ctxs_.rend(); it++) {
    (*it)->attachPipeline();
  }

  for (auto it = service_ctxs_.rbegin(); it != service_ctxs_.rend(); it++) {
    (*it)->attachPipeline();
  }

  notifyUpdate();
}

1、真正读取的read函数

拿 InboundContextImpl<Handler>举例。OUT也类似,不再单独举例。

void Pipeline::read(std::shared_ptr<DataPacket> packet) {
  if (!front_) {
    return;
  }
  front_->read(std::move(packet));
}
//这里的front对应一个InboundContextImpl
// InboundLink overrides
  void read(std::shared_ptr<DataPacket> packet) override {
    auto guard = this->pipelineWeak_.lock();
    //注意第一个参数this,作为参数传递给Handler了,Handler的read会调用
    this->handler_->read(this, std::move(packet));
  }
//InboundContextImpl 的read中会调用它的Handler,这个handler就是前面addFront时,作为
//模板参数和PipeLineBase一起传进来的

Handler内部也同样会调用read,下面以RtcpProcessorHandler 举例,代码如下:

void RtcpProcessorHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (packet->data);
  if (chead->isRtcp()) {
    if (chead->packettype == RTCP_Sender_PT) {  // Sender Report
      processor_->analyzeSr(chead);
    }
  } else {
    if (stats_->getNode()["total"].hasChild("bitrateCalculated")) {
       processor_->setPublisherBW(stats_->getNode()["total"]["bitrateCalculated"].value());
    }
  }
  processor_->checkRtcpFb();
  ctx->fireRead(std::move(packet));
}

可以看到RtcpProcessorHandler中会调用ctx->fireRead(),这里的ctx就是前面InboundContextImpl。fireRead中会调用

nextIn_即下个Handler,所以整个链条就串起来了。

  // InboundHandlerContext overrides
  void fireRead(std::shared_ptr<DataPacket> packet) override {
    auto guard = this->pipelineWeak_.lock();
    if (this->nextIn_) {
      this->nextIn_->read(std::move(packet));
    }
  }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

致一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值