Files
platform-external-webrtc/call/payload_router.cc
Stefan Holmer 1da4d79ba3 Move allocation and rtp conversion logic out of payload router.
Makes it easier to write tests, and allows for moving rtp module
ownership into the payload router in the future.

The RtpPayloadParams class is split into declaration and definition and
moved into separate files.

Bug: webrtc:9517
Change-Id: I8700628edff19abcacfe8d3a20e4ba7476f712ad
Reviewed-on: https://webrtc-review.googlesource.com/88564
Commit-Queue: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23983}
2018-07-16 13:34:37 +00:00

148 lines
5.1 KiB
C++

/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "call/payload_router.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) {
if (!info)
return absl::nullopt;
switch (info->codecType) {
case kVideoCodecVP8:
return absl::optional<size_t>(info->codecSpecific.VP8.simulcastIdx);
case kVideoCodecH264:
return absl::optional<size_t>(info->codecSpecific.H264.simulcast_idx);
case kVideoCodecMultiplex:
case kVideoCodecGeneric:
return absl::optional<size_t>(info->codecSpecific.generic.simulcast_idx);
default:
return absl::nullopt;
}
}
} // namespace
PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
const std::vector<uint32_t>& ssrcs,
int payload_type,
const std::map<uint32_t, RtpPayloadState>& states)
: active_(false), rtp_modules_(rtp_modules), payload_type_(payload_type) {
RTC_DCHECK_EQ(ssrcs.size(), rtp_modules.size());
// SSRCs are assumed to be sorted in the same order as |rtp_modules|.
for (uint32_t ssrc : ssrcs) {
// Restore state if it previously existed.
const RtpPayloadState* state = nullptr;
auto it = states.find(ssrc);
if (it != states.end()) {
state = &it->second;
}
params_.push_back(RtpPayloadParams(ssrc, state));
}
}
PayloadRouter::~PayloadRouter() {}
void PayloadRouter::SetActive(bool active) {
rtc::CritScope lock(&crit_);
if (active_ == active)
return;
const std::vector<bool> active_modules(rtp_modules_.size(), active);
SetActiveModules(active_modules);
}
void PayloadRouter::SetActiveModules(const std::vector<bool> active_modules) {
rtc::CritScope lock(&crit_);
RTC_DCHECK_EQ(rtp_modules_.size(), active_modules.size());
active_ = false;
for (size_t i = 0; i < active_modules.size(); ++i) {
if (active_modules[i]) {
active_ = true;
}
// Sends a kRtcpByeCode when going from true to false.
rtp_modules_[i]->SetSendingStatus(active_modules[i]);
// If set to false this module won't send media.
rtp_modules_[i]->SetSendingMediaStatus(active_modules[i]);
}
}
bool PayloadRouter::IsActive() {
rtc::CritScope lock(&crit_);
return active_ && !rtp_modules_.empty();
}
std::map<uint32_t, RtpPayloadState> PayloadRouter::GetRtpPayloadStates() const {
rtc::CritScope lock(&crit_);
std::map<uint32_t, RtpPayloadState> payload_states;
for (const auto& param : params_) {
payload_states[param.ssrc()] = param.state();
}
return payload_states;
}
EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) {
rtc::CritScope lock(&crit_);
RTC_DCHECK(!rtp_modules_.empty());
if (!active_)
return Result(Result::ERROR_SEND_FAILED);
size_t stream_index = GetSimulcastIdx(codec_specific_info).value_or(0);
RTC_DCHECK_LT(stream_index, rtp_modules_.size());
RTPVideoHeader rtp_video_header = params_[stream_index].GetRtpVideoHeader(
encoded_image, codec_specific_info);
uint32_t frame_id;
if (!rtp_modules_[stream_index]->Sending()) {
// The payload router could be active but this module isn't sending.
return Result(Result::ERROR_SEND_FAILED);
}
bool send_result = rtp_modules_[stream_index]->SendOutgoingData(
encoded_image._frameType, payload_type_, encoded_image._timeStamp,
encoded_image.capture_time_ms_, encoded_image._buffer,
encoded_image._length, fragmentation, &rtp_video_header, &frame_id);
if (!send_result)
return Result(Result::ERROR_SEND_FAILED);
return Result(Result::OK, frame_id);
}
void PayloadRouter::OnBitrateAllocationUpdated(
const VideoBitrateAllocation& bitrate) {
rtc::CritScope lock(&crit_);
if (IsActive()) {
if (rtp_modules_.size() == 1) {
// If spatial scalability is enabled, it is covered by a single stream.
rtp_modules_[0]->SetVideoBitrateAllocation(bitrate);
} else {
std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates =
bitrate.GetSimulcastAllocations();
// Simulcast is in use, split the VideoBitrateAllocation into one struct
// per rtp stream, moving over the temporal layer allocation.
for (size_t i = 0; i < rtp_modules_.size(); ++i) {
// The next spatial layer could be used if the current one is
// inactive.
if (layer_bitrates[i]) {
rtp_modules_[i]->SetVideoBitrateAllocation(*layer_bitrates[i]);
}
}
}
}
}
} // namespace webrtc