blob: cca4bd3418686557c13158c7ed26686d7101af8b [file] [log] [blame]
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +00001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Stefan Holmera2f15332018-07-11 17:11:31 +020011#include "call/payload_router.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "modules/rtp_rtcp/include/rtp_rtcp.h"
14#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
15#include "modules/video_coding/include/video_codec_interface.h"
16#include "rtc_base/checks.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000017
18namespace webrtc {
19
kjellander02b3d272016-04-20 05:05:54 -070020namespace {
Stefan Holmer1da4d792018-07-16 15:03:08 +020021absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) {
22 if (!info)
23 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -070024 switch (info->codecType) {
Stefan Holmer1da4d792018-07-16 15:03:08 +020025 case kVideoCodecVP8:
26 return absl::optional<size_t>(info->codecSpecific.VP8.simulcastIdx);
27 case kVideoCodecH264:
28 return absl::optional<size_t>(info->codecSpecific.H264.simulcast_idx);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080029 case kVideoCodecMultiplex:
kjellander02b3d272016-04-20 05:05:54 -070030 case kVideoCodecGeneric:
Stefan Holmer1da4d792018-07-16 15:03:08 +020031 return absl::optional<size_t>(info->codecSpecific.generic.simulcast_idx);
kjellander02b3d272016-04-20 05:05:54 -070032 default:
Stefan Holmer1da4d792018-07-16 15:03:08 +020033 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -070034 }
35}
36} // namespace
37
38PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
Åsa Persson4bece9a2017-10-06 10:04:04 +020039 const std::vector<uint32_t>& ssrcs,
40 int payload_type,
41 const std::map<uint32_t, RtpPayloadState>& states)
Niels Möllerbb894ff2018-03-15 12:28:53 +010042 : active_(false), rtp_modules_(rtp_modules), payload_type_(payload_type) {
Åsa Persson4bece9a2017-10-06 10:04:04 +020043 RTC_DCHECK_EQ(ssrcs.size(), rtp_modules.size());
44 // SSRCs are assumed to be sorted in the same order as |rtp_modules|.
45 for (uint32_t ssrc : ssrcs) {
46 // Restore state if it previously existed.
47 const RtpPayloadState* state = nullptr;
48 auto it = states.find(ssrc);
49 if (it != states.end()) {
50 state = &it->second;
51 }
52 params_.push_back(RtpPayloadParams(ssrc, state));
53 }
Per83d09102016-04-15 14:59:13 +020054}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000055
56PayloadRouter::~PayloadRouter() {}
57
sprang1a646ee2016-12-01 06:34:11 -080058void PayloadRouter::SetActive(bool active) {
Tommi97888bd2016-01-21 23:24:59 +010059 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +010060 if (active_ == active)
61 return;
Seth Hampsoncc7125f2018-02-02 08:46:16 -080062 const std::vector<bool> active_modules(rtp_modules_.size(), active);
63 SetActiveModules(active_modules);
64}
Per512ecb32016-09-23 15:52:06 +020065
Seth Hampsoncc7125f2018-02-02 08:46:16 -080066void PayloadRouter::SetActiveModules(const std::vector<bool> active_modules) {
67 rtc::CritScope lock(&crit_);
68 RTC_DCHECK_EQ(rtp_modules_.size(), active_modules.size());
69 active_ = false;
70 for (size_t i = 0; i < active_modules.size(); ++i) {
71 if (active_modules[i]) {
72 active_ = true;
73 }
74 // Sends a kRtcpByeCode when going from true to false.
75 rtp_modules_[i]->SetSendingStatus(active_modules[i]);
76 // If set to false this module won't send media.
77 rtp_modules_[i]->SetSendingMediaStatus(active_modules[i]);
Per512ecb32016-09-23 15:52:06 +020078 }
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000079}
80
sprang1a646ee2016-12-01 06:34:11 -080081bool PayloadRouter::IsActive() {
Tommi97888bd2016-01-21 23:24:59 +010082 rtc::CritScope lock(&crit_);
mflodman@webrtc.org47d657b2015-02-19 10:29:32 +000083 return active_ && !rtp_modules_.empty();
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000084}
85
Åsa Persson4bece9a2017-10-06 10:04:04 +020086std::map<uint32_t, RtpPayloadState> PayloadRouter::GetRtpPayloadStates() const {
87 rtc::CritScope lock(&crit_);
88 std::map<uint32_t, RtpPayloadState> payload_states;
89 for (const auto& param : params_) {
90 payload_states[param.ssrc()] = param.state();
91 }
92 return payload_states;
93}
94
Sergey Ulanov525df3f2016-08-02 17:46:41 -070095EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
96 const EncodedImage& encoded_image,
97 const CodecSpecificInfo* codec_specific_info,
98 const RTPFragmentationHeader* fragmentation) {
Tommi97888bd2016-01-21 23:24:59 +010099 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +0100100 RTC_DCHECK(!rtp_modules_.empty());
Per512ecb32016-09-23 15:52:06 +0200101 if (!active_)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700102 return Result(Result::ERROR_SEND_FAILED);
mflodman@webrtc.org50e28162015-02-23 07:45:11 +0000103
Stefan Holmer1da4d792018-07-16 15:03:08 +0200104 size_t stream_index = GetSimulcastIdx(codec_specific_info).value_or(0);
sergeyu7b9feee2016-11-17 16:16:14 -0800105 RTC_DCHECK_LT(stream_index, rtp_modules_.size());
Stefan Holmer1da4d792018-07-16 15:03:08 +0200106 RTPVideoHeader rtp_video_header = params_[stream_index].GetRtpVideoHeader(
107 encoded_image, codec_specific_info);
Niels Möllerbb894ff2018-03-15 12:28:53 +0100108
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700109 uint32_t frame_id;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800110 if (!rtp_modules_[stream_index]->Sending()) {
111 // The payload router could be active but this module isn't sending.
112 return Result(Result::ERROR_SEND_FAILED);
113 }
sergeyu7b9feee2016-11-17 16:16:14 -0800114 bool send_result = rtp_modules_[stream_index]->SendOutgoingData(
kjellander02b3d272016-04-20 05:05:54 -0700115 encoded_image._frameType, payload_type_, encoded_image._timeStamp,
116 encoded_image.capture_time_ms_, encoded_image._buffer,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700117 encoded_image._length, fragmentation, &rtp_video_header, &frame_id);
sergeyu7b9feee2016-11-17 16:16:14 -0800118 if (!send_result)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700119 return Result(Result::ERROR_SEND_FAILED);
120
121 return Result(Result::OK, frame_id);
mflodman@webrtc.orga4ef2ce2015-02-12 09:54:18 +0000122}
123
sprang1a646ee2016-12-01 06:34:11 -0800124void PayloadRouter::OnBitrateAllocationUpdated(
Erik Språng566124a2018-04-23 12:32:22 +0200125 const VideoBitrateAllocation& bitrate) {
sprang1a646ee2016-12-01 06:34:11 -0800126 rtc::CritScope lock(&crit_);
127 if (IsActive()) {
128 if (rtp_modules_.size() == 1) {
129 // If spatial scalability is enabled, it is covered by a single stream.
130 rtp_modules_[0]->SetVideoBitrateAllocation(bitrate);
131 } else {
Stefan Holmer1da4d792018-07-16 15:03:08 +0200132 std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates =
133 bitrate.GetSimulcastAllocations();
Erik Språng566124a2018-04-23 12:32:22 +0200134 // Simulcast is in use, split the VideoBitrateAllocation into one struct
135 // per rtp stream, moving over the temporal layer allocation.
Stefan Holmer1da4d792018-07-16 15:03:08 +0200136 for (size_t i = 0; i < rtp_modules_.size(); ++i) {
137 // The next spatial layer could be used if the current one is
138 // inactive.
139 if (layer_bitrates[i]) {
140 rtp_modules_[i]->SetVideoBitrateAllocation(*layer_bitrates[i]);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800141 }
sprang1a646ee2016-12-01 06:34:11 -0800142 }
143 }
144 }
145}
146
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000147} // namespace webrtc