void SenderBandwidthEstimationHandler::write(Context *ctx, std::shared_ptr<dataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);
  if (!chead->isRtcp() && packet->type == VIDEO_PACKET) {
    period_packets_sent_++;
  } else if (chead->getPacketType() == RTCP_Sender_PT &&
      chead->getSSRC() == connection_->getVideoSinkSSRC()) {
    analyzeSr(chead);
  }
  ctx->fireWrite(packet);
}
void RtcpFeedbackGenerationHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) {
  // Pass packets to RR and NACK Generator
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);

  if (!initialized_) {
    ctx->fireRead(std::move(packet));
    return;
  }

  if (chead->getPacketType() == RTCP_Sender_PT) {
    uint32_t ssrc = chead->getSSRC();
    auto generator_it = generators_map_.find(ssrc);
    if (generator_it != generators_map_.end()) {
      generator_it->second->rr_generator->handleSr(packet);
    } else {
      ELOG_DEBUG("message: no RrGenerator found, ssrc: %u", ssrc);
    }
    ctx->fireRead(std::move(packet));
    return;
  }
  bool should_send_rr = false;
  bool should_send_nack = false;

  if (!chead->isRtcp()) {
    RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data);
    uint32_t ssrc = head->getSSRC();
    auto generator_it = generators_map_.find(ssrc);
    if (generator_it != generators_map_.end()) {
        should_send_rr = generator_it->second->rr_generator->handleRtpPacket(packet);
        if (nacks_enabled_) {
          should_send_nack = generator_it->second->nack_generator->handleRtpPacket(packet);
        }
    } else {
      ELOG_DEBUG("message: no Generator found, ssrc: %u", ssrc);
    }

    if (should_send_rr || should_send_nack) {
      ELOG_DEBUG("message: Should send Rtcp, ssrc %u", ssrc);
      std::shared_ptr<DataPacket> rtcp_packet = generator_it->second->rr_generator->generateReceiverReport();
      if (nacks_enabled_ && generator_it->second->nack_generator != nullptr) {
        generator_it->second->nack_generator->addNackPacketToRr(rtcp_packet);
      }
      ctx->fireWrite(std::move(rtcp_packet));
    }
  }
  ctx->fireRead(std::move(packet));
}
void SenderBandwidthEstimationHandler::read(Context *ctx, std::shared_ptr<dataPacket> packet) {
  RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data);
  if (chead->isFeedback() && chead->getSourceSSRC() == connection_->getVideoSinkSSRC()) {
    char* packet_pointer = packet->data;
    int rtcp_length = 0;
    int total_length = 0;
    int current_block = 0;

    do {
      packet_pointer+=rtcp_length;
      chead = reinterpret_cast<RtcpHeader*>(packet_pointer);
      rtcp_length = (ntohs(chead->length) + 1) * 4;
      total_length += rtcp_length;
      ELOG_DEBUG("%s ssrc %u, sourceSSRC %u, PacketType %u", connection_->toLog(),
          chead->getSSRC(),
          chead->getSourceSSRC(),
          chead->getPacketType());
      switch (chead->packettype) {
        case RTCP_Receiver_PT:
          {
            ELOG_DEBUG("%s, Analyzing Video RR: PacketLost %u, Ratio %u, current_block %d, blocks %d"
                ", sourceSSRC %u, ssrc %u",
                connection_->toLog(),
                chead->getLostPackets(),
                chead->getFractionLost(),
                current_block,
                chead->getBlockCount(),
                chead->getSourceSSRC(),
                chead->getSSRC());
            // calculate RTT + Update receiver block
            uint32_t delay_since_last_ms = (chead->getDelaySinceLastSr() * 1000) / 65536;
            int64_t now_ms = ClockUtils::timePointToMs(clock::now());
            uint32_t last_sr = chead->getLastSr();

            auto value = std::find_if(sr_delay_data_.begin(), sr_delay_data_.end(),
                [last_sr](const std::shared_ptr<SrDelayData> sr_info) {
                return sr_info->sr_ntp == last_sr;
                });
            if (value != sr_delay_data_.end()) {
                uint32_t delay = now_ms - (*value)->sr_send_time - delay_since_last_ms;
                sender_bwe_->UpdateReceiverBlock(chead->getFractionLost(),
                    delay, period_packets_sent_, now_ms);
                period_packets_sent_ = 0;
                updateEstimate();
            }
          }
          break;
        case RTCP_PS_Feedback_PT:
          {
            if (chead->getBlockCount() == RTCP_AFB) {
              char *uniqueId = reinterpret_cast<char*>(&chead->report.rembPacket.uniqueid);
              if (!strncmp(uniqueId, "REMB", 4)) {
                int64_t now_ms = ClockUtils::timePointToMs(clock::now());
                uint64_t bitrate = chead->getBrMantis() << chead->getBrExp();
                ELOG_DEBUG("%s message: Updating Estimate with REMB, bitrate %llu", connection_->toLog(),
                    bitrate);
                sender_bwe_->UpdateReceiverEstimate(now_ms, bitrate);
                sender_bwe_->UpdateEstimate(now_ms);
                updateEstimate();
              } else {
                ELOG_DEBUG("%s message: Unsupported AFB Packet not REMB", connection_->toLog());
              }
            }
          }
          break;
        default:
          break;
      }
      current_block++;
    } while (total_length < packet->length);
  }
  ctx->fireRead(packet);
}