blob: c604c24921731e61010017229b609cd16355d04f [file] [log] [blame]
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001/*
2 * Copyright (c) 2012 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_receiver_impl.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000012
13#include <assert.h>
14#include <math.h>
15#include <stdlib.h>
16#include <string.h>
17
hbos8d609f62017-04-10 07:39:05 -070018#include <set>
19#include <vector>
20
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "common_types.h"
22#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
23#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
24#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
25#include "rtc_base/logging.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000026
27namespace webrtc {
28
pbos@webrtc.org62bafae2014-07-08 12:10:51 +000029using RtpUtility::Payload;
wu@webrtc.org822fbd82013-08-15 23:38:54 +000030
hbos8d609f62017-04-10 07:39:05 -070031// Only return the sources in the last 10 seconds.
32const int64_t kGetSourcesTimeoutMs = 10000;
33
wu@webrtc.org822fbd82013-08-15 23:38:54 +000034RtpReceiver* RtpReceiver::CreateVideoReceiver(
Peter Boströmac547a62015-09-17 23:03:57 +020035 Clock* clock,
wu@webrtc.org822fbd82013-08-15 23:38:54 +000036 RtpData* incoming_payload_callback,
37 RtpFeedback* incoming_messages_callback,
38 RTPPayloadRegistry* rtp_payload_registry) {
nisse7fcdb6d2017-06-01 00:30:55 -070039 RTC_DCHECK(incoming_payload_callback != nullptr);
wu@webrtc.org822fbd82013-08-15 23:38:54 +000040 if (!incoming_messages_callback)
41 incoming_messages_callback = NullObjectRtpFeedback();
42 return new RtpReceiverImpl(
solenberg1d031392016-03-30 02:42:32 -070043 clock, incoming_messages_callback, rtp_payload_registry,
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000044 RTPReceiverStrategy::CreateVideoStrategy(incoming_payload_callback));
wu@webrtc.org822fbd82013-08-15 23:38:54 +000045}
46
47RtpReceiver* RtpReceiver::CreateAudioReceiver(
Peter Boströmac547a62015-09-17 23:03:57 +020048 Clock* clock,
solenberg1d031392016-03-30 02:42:32 -070049 RtpData* incoming_payload_callback,
50 RtpFeedback* incoming_messages_callback,
51 RTPPayloadRegistry* rtp_payload_registry) {
nisse7fcdb6d2017-06-01 00:30:55 -070052 RTC_DCHECK(incoming_payload_callback != nullptr);
solenberg1d031392016-03-30 02:42:32 -070053 if (!incoming_messages_callback)
54 incoming_messages_callback = NullObjectRtpFeedback();
55 return new RtpReceiverImpl(
56 clock, incoming_messages_callback, rtp_payload_registry,
57 RTPReceiverStrategy::CreateAudioStrategy(incoming_payload_callback));
58}
59
hbos8d609f62017-04-10 07:39:05 -070060RtpReceiverImpl::RtpReceiverImpl(Clock* clock,
61 RtpFeedback* incoming_messages_callback,
62 RTPPayloadRegistry* rtp_payload_registry,
63 RTPReceiverStrategy* rtp_media_receiver)
wu@webrtc.org822fbd82013-08-15 23:38:54 +000064 : clock_(clock),
65 rtp_payload_registry_(rtp_payload_registry),
66 rtp_media_receiver_(rtp_media_receiver),
wu@webrtc.org822fbd82013-08-15 23:38:54 +000067 cb_rtp_feedback_(incoming_messages_callback),
wu@webrtc.org822fbd82013-08-15 23:38:54 +000068 last_receive_time_(0),
69 last_received_payload_length_(0),
70 ssrc_(0),
71 num_csrcs_(0),
72 current_remote_csrc_(),
73 last_received_timestamp_(0),
stefan@webrtc.org48df3812013-11-08 15:18:52 +000074 last_received_frame_time_ms_(-1),
Fredrik Solenbergcd6ae662016-05-11 13:05:05 +020075 last_received_sequence_number_(0) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +000076 assert(incoming_messages_callback);
77
78 memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_));
wu@webrtc.org822fbd82013-08-15 23:38:54 +000079}
80
81RtpReceiverImpl::~RtpReceiverImpl() {
82 for (int i = 0; i < num_csrcs_; ++i) {
Peter Boströmac547a62015-09-17 23:03:57 +020083 cb_rtp_feedback_->OnIncomingCSRCChanged(current_remote_csrc_[i], false);
wu@webrtc.org822fbd82013-08-15 23:38:54 +000084 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +000085}
86
magjed56124bd2016-11-24 09:34:46 -080087int32_t RtpReceiverImpl::RegisterReceivePayload(const CodecInst& audio_codec) {
danilchap7c9426c2016-04-14 03:05:31 -070088 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +000089
90 // TODO(phoglund): Try to streamline handling of the RED codec and some other
91 // cases which makes it necessary to keep track of whether we created a
92 // payload or not.
93 bool created_new_payload = false;
94 int32_t result = rtp_payload_registry_->RegisterReceivePayload(
magjed56124bd2016-11-24 09:34:46 -080095 audio_codec, &created_new_payload);
wu@webrtc.org822fbd82013-08-15 23:38:54 +000096 if (created_new_payload) {
magjed56124bd2016-11-24 09:34:46 -080097 if (rtp_media_receiver_->OnNewPayloadTypeCreated(audio_codec) != 0) {
98 LOG(LS_ERROR) << "Failed to register payload: " << audio_codec.plname
99 << "/" << static_cast<int>(audio_codec.pltype);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000100 return -1;
101 }
102 }
103 return result;
104}
105
magjed6b272c52016-11-25 02:29:39 -0800106int32_t RtpReceiverImpl::RegisterReceivePayload(const VideoCodec& video_codec) {
107 rtc::CritScope lock(&critical_section_rtp_receiver_);
108 return rtp_payload_registry_->RegisterReceivePayload(video_codec);
109}
110
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000111int32_t RtpReceiverImpl::DeRegisterReceivePayload(
112 const int8_t payload_type) {
danilchap7c9426c2016-04-14 03:05:31 -0700113 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000114 return rtp_payload_registry_->DeRegisterReceivePayload(payload_type);
115}
116
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000117uint32_t RtpReceiverImpl::SSRC() const {
danilchap7c9426c2016-04-14 03:05:31 -0700118 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000119 return ssrc_;
120}
121
122// Get remote CSRC.
123int32_t RtpReceiverImpl::CSRCs(uint32_t array_of_csrcs[kRtpCsrcSize]) const {
danilchap7c9426c2016-04-14 03:05:31 -0700124 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000125
126 assert(num_csrcs_ <= kRtpCsrcSize);
127
128 if (num_csrcs_ > 0) {
129 memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t)*num_csrcs_);
130 }
131 return num_csrcs_;
132}
133
134int32_t RtpReceiverImpl::Energy(
135 uint8_t array_of_energy[kRtpCsrcSize]) const {
136 return rtp_media_receiver_->Energy(array_of_energy);
137}
138
139bool RtpReceiverImpl::IncomingRtpPacket(
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000140 const RTPHeader& rtp_header,
141 const uint8_t* payload,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000142 size_t payload_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000143 PayloadUnion payload_specific,
144 bool in_order) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000145 // Trigger our callbacks.
146 CheckSSRCChanged(rtp_header);
147
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000148 int8_t first_payload_byte = payload_length > 0 ? payload[0] : 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000149 bool is_red = false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000150
danilchap6db6cdc2015-12-15 02:54:47 -0800151 if (CheckPayloadChanged(rtp_header, first_payload_byte, &is_red,
pbosd4362982015-07-07 08:32:48 -0700152 &payload_specific) == -1) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000153 if (payload_length == 0) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000154 // OK, keep-alive packet.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000155 return true;
156 }
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000157 LOG(LS_WARNING) << "Receiving invalid payload type.";
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000158 return false;
159 }
160
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000161 WebRtcRTPHeader webrtc_rtp_header;
162 memset(&webrtc_rtp_header, 0, sizeof(webrtc_rtp_header));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000163 webrtc_rtp_header.header = rtp_header;
164 CheckCSRC(webrtc_rtp_header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000165
zstein2b706342017-08-24 14:52:17 -0700166 auto audio_level =
167 rtp_header.extension.hasAudioLevel
168 ? rtc::Optional<uint8_t>(rtp_header.extension.audioLevel)
169 : rtc::Optional<uint8_t>();
170 UpdateSources(audio_level);
hbos8d609f62017-04-10 07:39:05 -0700171
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000172 size_t payload_data_length = payload_length - rtp_header.paddingLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000173
174 bool is_first_packet_in_frame = false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000175 {
danilchap7c9426c2016-04-14 03:05:31 -0700176 rtc::CritScope lock(&critical_section_rtp_receiver_);
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000177 if (HaveReceivedFrame()) {
178 is_first_packet_in_frame =
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000179 last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000180 last_received_timestamp_ != rtp_header.timestamp;
181 } else {
182 is_first_packet_in_frame = true;
183 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000184 }
185
186 int32_t ret_val = rtp_media_receiver_->ParseRtpPacket(
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000187 &webrtc_rtp_header, payload_specific, is_red, payload, payload_length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000188 clock_->TimeInMilliseconds(), is_first_packet_in_frame);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000189
190 if (ret_val < 0) {
191 return false;
192 }
193
194 {
danilchap7c9426c2016-04-14 03:05:31 -0700195 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000196
197 last_receive_time_ = clock_->TimeInMilliseconds();
198 last_received_payload_length_ = payload_data_length;
199
200 if (in_order) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000201 if (last_received_timestamp_ != rtp_header.timestamp) {
202 last_received_timestamp_ = rtp_header.timestamp;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000203 last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
204 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000205 last_received_sequence_number_ = rtp_header.sequenceNumber;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000206 }
207 }
208 return true;
209}
210
danilchap799a9d02016-09-22 03:36:27 -0700211TelephoneEventHandler* RtpReceiverImpl::GetTelephoneEventHandler() {
212 return rtp_media_receiver_->GetTelephoneEventHandler();
213}
214
hbos8d609f62017-04-10 07:39:05 -0700215std::vector<RtpSource> RtpReceiverImpl::GetSources() const {
zhihuang04262222017-04-11 11:28:10 -0700216 rtc::CritScope lock(&critical_section_rtp_receiver_);
217
hbos8d609f62017-04-10 07:39:05 -0700218 int64_t now_ms = clock_->TimeInMilliseconds();
219 std::vector<RtpSource> sources;
220
zhihuang04262222017-04-11 11:28:10 -0700221 RTC_DCHECK(std::is_sorted(ssrc_sources_.begin(), ssrc_sources_.end(),
222 [](const RtpSource& lhs, const RtpSource& rhs) {
223 return lhs.timestamp_ms() < rhs.timestamp_ms();
224 }));
225 RTC_DCHECK(std::is_sorted(csrc_sources_.begin(), csrc_sources_.end(),
226 [](const RtpSource& lhs, const RtpSource& rhs) {
227 return lhs.timestamp_ms() < rhs.timestamp_ms();
228 }));
hbos8d609f62017-04-10 07:39:05 -0700229
zhihuang04262222017-04-11 11:28:10 -0700230 std::set<uint32_t> selected_ssrcs;
231 for (auto rit = ssrc_sources_.rbegin(); rit != ssrc_sources_.rend(); ++rit) {
232 if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) {
233 break;
hbos8d609f62017-04-10 07:39:05 -0700234 }
zhihuang04262222017-04-11 11:28:10 -0700235 if (selected_ssrcs.insert(rit->source_id()).second) {
hbos8d609f62017-04-10 07:39:05 -0700236 sources.push_back(*rit);
237 }
zhihuang04262222017-04-11 11:28:10 -0700238 }
hbos8d609f62017-04-10 07:39:05 -0700239
zhihuang04262222017-04-11 11:28:10 -0700240 for (auto rit = csrc_sources_.rbegin(); rit != csrc_sources_.rend(); ++rit) {
241 if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) {
242 break;
243 }
244 sources.push_back(*rit);
245 }
hbos8d609f62017-04-10 07:39:05 -0700246 return sources;
247}
248
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000249bool RtpReceiverImpl::Timestamp(uint32_t* timestamp) const {
danilchap7c9426c2016-04-14 03:05:31 -0700250 rtc::CritScope lock(&critical_section_rtp_receiver_);
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000251 if (!HaveReceivedFrame())
252 return false;
253 *timestamp = last_received_timestamp_;
254 return true;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000255}
256
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000257bool RtpReceiverImpl::LastReceivedTimeMs(int64_t* receive_time_ms) const {
danilchap7c9426c2016-04-14 03:05:31 -0700258 rtc::CritScope lock(&critical_section_rtp_receiver_);
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000259 if (!HaveReceivedFrame())
260 return false;
261 *receive_time_ms = last_received_frame_time_ms_;
262 return true;
263}
264
265bool RtpReceiverImpl::HaveReceivedFrame() const {
266 return last_received_frame_time_ms_ >= 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000267}
268
269// Implementation note: must not hold critsect when called.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000270void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader& rtp_header) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000271 bool new_ssrc = false;
272 bool re_initialize_decoder = false;
273 char payload_name[RTP_PAYLOAD_NAME_SIZE];
Peter Kasting69558702016-01-12 16:26:35 -0800274 size_t channels = 1;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000275 uint32_t rate = 0;
276
277 {
danilchap7c9426c2016-04-14 03:05:31 -0700278 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000279
280 int8_t last_received_payload_type =
281 rtp_payload_registry_->last_received_payload_type();
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000282 if (ssrc_ != rtp_header.ssrc ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000283 (last_received_payload_type == -1 && ssrc_ == 0)) {
284 // We need the payload_type_ to make the call if the remote SSRC is 0.
285 new_ssrc = true;
286
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000287 last_received_timestamp_ = 0;
288 last_received_sequence_number_ = 0;
stefan@webrtc.org48df3812013-11-08 15:18:52 +0000289 last_received_frame_time_ms_ = -1;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000290
291 // Do we have a SSRC? Then the stream is restarted.
292 if (ssrc_ != 0) {
293 // Do we have the same codec? Then re-initialize coder.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000294 if (rtp_header.payloadType == last_received_payload_type) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000295 re_initialize_decoder = true;
296
danilchap5c1def82015-12-10 09:51:54 -0800297 const Payload* payload = rtp_payload_registry_->PayloadTypeToPayload(
298 rtp_header.payloadType);
299 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000300 return;
301 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000302 payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
303 strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
304 if (payload->audio) {
305 channels = payload->typeSpecific.Audio.channels;
306 rate = payload->typeSpecific.Audio.rate;
307 }
308 }
309 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000310 ssrc_ = rtp_header.ssrc;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000311 }
312 }
313
314 if (new_ssrc) {
315 // We need to get this to our RTCP sender and receiver.
316 // We need to do this outside critical section.
Peter Boströmac547a62015-09-17 23:03:57 +0200317 cb_rtp_feedback_->OnIncomingSSRCChanged(rtp_header.ssrc);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000318 }
319
320 if (re_initialize_decoder) {
Peter Boströmac547a62015-09-17 23:03:57 +0200321 if (-1 ==
322 cb_rtp_feedback_->OnInitializeDecoder(
323 rtp_header.payloadType, payload_name,
324 rtp_header.payload_type_frequency, channels, rate)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000325 // New stream, same codec.
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000326 LOG(LS_ERROR) << "Failed to create decoder for payload type: "
pkasting@chromium.org026b8922015-01-30 19:53:42 +0000327 << static_cast<int>(rtp_header.payloadType);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000328 }
329 }
330}
331
332// Implementation note: must not hold critsect when called.
333// TODO(phoglund): Move as much as possible of this code path into the media
334// specific receivers. Basically this method goes through a lot of trouble to
335// compute something which is only used by the media specific parts later. If
336// this code path moves we can get rid of some of the rtp_receiver ->
337// media_specific interface (such as CheckPayloadChange, possibly get/set
338// last known payload).
pbosd4362982015-07-07 08:32:48 -0700339int32_t RtpReceiverImpl::CheckPayloadChanged(const RTPHeader& rtp_header,
340 const int8_t first_payload_byte,
danilchap6db6cdc2015-12-15 02:54:47 -0800341 bool* is_red,
pbosd4362982015-07-07 08:32:48 -0700342 PayloadUnion* specific_payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000343 bool re_initialize_decoder = false;
344
345 char payload_name[RTP_PAYLOAD_NAME_SIZE];
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000346 int8_t payload_type = rtp_header.payloadType;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000347
348 {
danilchap7c9426c2016-04-14 03:05:31 -0700349 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000350
351 int8_t last_received_payload_type =
352 rtp_payload_registry_->last_received_payload_type();
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000353 // TODO(holmer): Remove this code when RED parsing has been broken out from
354 // RtpReceiverAudio.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000355 if (payload_type != last_received_payload_type) {
356 if (rtp_payload_registry_->red_payload_type() == payload_type) {
357 // Get the real codec payload type.
358 payload_type = first_payload_byte & 0x7f;
danilchap6db6cdc2015-12-15 02:54:47 -0800359 *is_red = true;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000360
361 if (rtp_payload_registry_->red_payload_type() == payload_type) {
362 // Invalid payload type, traced by caller. If we proceeded here,
363 // this would be set as |_last_received_payload_type|, and we would no
364 // longer catch corrupt packets at this level.
365 return -1;
366 }
367
368 // When we receive RED we need to check the real payload type.
369 if (payload_type == last_received_payload_type) {
370 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
371 return 0;
372 }
373 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000374 bool should_discard_changes = false;
375
376 rtp_media_receiver_->CheckPayloadChanged(
pbosd4362982015-07-07 08:32:48 -0700377 payload_type, specific_payload,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000378 &should_discard_changes);
379
380 if (should_discard_changes) {
danilchap6db6cdc2015-12-15 02:54:47 -0800381 *is_red = false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000382 return 0;
383 }
384
danilchap5c1def82015-12-10 09:51:54 -0800385 const Payload* payload =
386 rtp_payload_registry_->PayloadTypeToPayload(payload_type);
387 if (!payload) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000388 // Not a registered payload type.
389 return -1;
390 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000391 payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
392 strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
393
394 rtp_payload_registry_->set_last_received_payload_type(payload_type);
395
396 re_initialize_decoder = true;
397
398 rtp_media_receiver_->SetLastMediaSpecificPayload(payload->typeSpecific);
399 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
400
401 if (!payload->audio) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000402 bool media_type_unchanged =
403 rtp_payload_registry_->ReportMediaPayloadType(payload_type);
404 if (media_type_unchanged) {
405 // Only reset the decoder if the media codec type has changed.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000406 re_initialize_decoder = false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000407 }
408 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000409 } else {
410 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
danilchap6db6cdc2015-12-15 02:54:47 -0800411 *is_red = false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000412 }
413 } // End critsect.
414
415 if (re_initialize_decoder) {
Peter Boströmac547a62015-09-17 23:03:57 +0200416 if (-1 ==
417 rtp_media_receiver_->InvokeOnInitializeDecoder(
418 cb_rtp_feedback_, payload_type, payload_name, *specific_payload)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000419 return -1; // Wrong payload type.
420 }
421 }
422 return 0;
423}
424
425// Implementation note: must not hold critsect when called.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000426void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000427 int32_t num_csrcs_diff = 0;
428 uint32_t old_remote_csrc[kRtpCsrcSize];
429 uint8_t old_num_csrcs = 0;
430
431 {
danilchap7c9426c2016-04-14 03:05:31 -0700432 rtc::CritScope lock(&critical_section_rtp_receiver_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000433
434 if (!rtp_media_receiver_->ShouldReportCsrcChanges(
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000435 rtp_header.header.payloadType)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000436 return;
437 }
438 old_num_csrcs = num_csrcs_;
439 if (old_num_csrcs > 0) {
440 // Make a copy of old.
441 memcpy(old_remote_csrc, current_remote_csrc_,
442 num_csrcs_ * sizeof(uint32_t));
443 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000444 const uint8_t num_csrcs = rtp_header.header.numCSRCs;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000445 if ((num_csrcs > 0) && (num_csrcs <= kRtpCsrcSize)) {
446 // Copy new.
447 memcpy(current_remote_csrc_,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000448 rtp_header.header.arrOfCSRCs,
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000449 num_csrcs * sizeof(uint32_t));
450 }
451 if (num_csrcs > 0 || old_num_csrcs > 0) {
452 num_csrcs_diff = num_csrcs - old_num_csrcs;
453 num_csrcs_ = num_csrcs; // Update stored CSRCs.
454 } else {
455 // No change.
456 return;
457 }
458 } // End critsect.
459
460 bool have_called_callback = false;
461 // Search for new CSRC in old array.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000462 for (uint8_t i = 0; i < rtp_header.header.numCSRCs; ++i) {
463 const uint32_t csrc = rtp_header.header.arrOfCSRCs[i];
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000464
465 bool found_match = false;
466 for (uint8_t j = 0; j < old_num_csrcs; ++j) {
467 if (csrc == old_remote_csrc[j]) { // old list
468 found_match = true;
469 break;
470 }
471 }
472 if (!found_match && csrc) {
473 // Didn't find it, report it as new.
474 have_called_callback = true;
Peter Boströmac547a62015-09-17 23:03:57 +0200475 cb_rtp_feedback_->OnIncomingCSRCChanged(csrc, true);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000476 }
477 }
478 // Search for old CSRC in new array.
479 for (uint8_t i = 0; i < old_num_csrcs; ++i) {
480 const uint32_t csrc = old_remote_csrc[i];
481
482 bool found_match = false;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000483 for (uint8_t j = 0; j < rtp_header.header.numCSRCs; ++j) {
484 if (csrc == rtp_header.header.arrOfCSRCs[j]) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000485 found_match = true;
486 break;
487 }
488 }
489 if (!found_match && csrc) {
490 // Did not find it, report as removed.
491 have_called_callback = true;
Peter Boströmac547a62015-09-17 23:03:57 +0200492 cb_rtp_feedback_->OnIncomingCSRCChanged(csrc, false);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000493 }
494 }
495 if (!have_called_callback) {
496 // If the CSRC list contain non-unique entries we will end up here.
497 // Using CSRC 0 to signal this event, not interop safe, other
498 // implementations might have CSRC 0 as a valid value.
499 if (num_csrcs_diff > 0) {
Peter Boströmac547a62015-09-17 23:03:57 +0200500 cb_rtp_feedback_->OnIncomingCSRCChanged(0, true);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000501 } else if (num_csrcs_diff < 0) {
Peter Boströmac547a62015-09-17 23:03:57 +0200502 cb_rtp_feedback_->OnIncomingCSRCChanged(0, false);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000503 }
504 }
505}
506
zstein2b706342017-08-24 14:52:17 -0700507void RtpReceiverImpl::UpdateSources(
508 const rtc::Optional<uint8_t>& ssrc_audio_level) {
hbos8d609f62017-04-10 07:39:05 -0700509 rtc::CritScope lock(&critical_section_rtp_receiver_);
510 int64_t now_ms = clock_->TimeInMilliseconds();
511
512 for (size_t i = 0; i < num_csrcs_; ++i) {
513 auto map_it = iterator_by_csrc_.find(current_remote_csrc_[i]);
514 if (map_it == iterator_by_csrc_.end()) {
515 // If it is a new CSRC, append a new object to the end of the list.
516 csrc_sources_.emplace_back(now_ms, current_remote_csrc_[i],
517 RtpSourceType::CSRC);
518 } else {
519 // If it is an existing CSRC, move the object to the end of the list.
520 map_it->second->update_timestamp_ms(now_ms);
521 csrc_sources_.splice(csrc_sources_.end(), csrc_sources_, map_it->second);
522 }
523 // Update the unordered_map.
524 iterator_by_csrc_[current_remote_csrc_[i]] = std::prev(csrc_sources_.end());
525 }
526
527 // If this is the first packet or the SSRC is changed, insert a new
528 // contributing source that uses the SSRC.
529 if (ssrc_sources_.empty() || ssrc_sources_.rbegin()->source_id() != ssrc_) {
530 ssrc_sources_.emplace_back(now_ms, ssrc_, RtpSourceType::SSRC);
531 } else {
532 ssrc_sources_.rbegin()->update_timestamp_ms(now_ms);
533 }
534
zstein2b706342017-08-24 14:52:17 -0700535 ssrc_sources_.back().set_audio_level(ssrc_audio_level);
536
hbos8d609f62017-04-10 07:39:05 -0700537 RemoveOutdatedSources(now_ms);
538}
539
540void RtpReceiverImpl::RemoveOutdatedSources(int64_t now_ms) {
541 std::list<RtpSource>::iterator it;
542 for (it = csrc_sources_.begin(); it != csrc_sources_.end(); ++it) {
543 if ((now_ms - it->timestamp_ms()) <= kGetSourcesTimeoutMs) {
544 break;
545 }
546 iterator_by_csrc_.erase(it->source_id());
547 }
548 csrc_sources_.erase(csrc_sources_.begin(), it);
549
550 std::vector<RtpSource>::iterator vec_it;
551 for (vec_it = ssrc_sources_.begin(); vec_it != ssrc_sources_.end();
552 ++vec_it) {
553 if ((now_ms - vec_it->timestamp_ms()) <= kGetSourcesTimeoutMs) {
554 break;
555 }
556 }
557 ssrc_sources_.erase(ssrc_sources_.begin(), vec_it);
558}
559
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000560} // namespace webrtc