2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h"
18 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
19 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
20 #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
21 #include "webrtc/system_wrappers/interface/trace.h"
25 using ModuleRTPUtility::GetCurrentRTP;
26 using ModuleRTPUtility::Payload;
27 using ModuleRTPUtility::RTPPayloadParser;
28 using ModuleRTPUtility::StringCompare;
30 RtpReceiver* RtpReceiver::CreateVideoReceiver(
32 RtpData* incoming_payload_callback,
33 RtpFeedback* incoming_messages_callback,
34 RTPPayloadRegistry* rtp_payload_registry) {
35 if (!incoming_payload_callback)
36 incoming_payload_callback = NullObjectRtpData();
37 if (!incoming_messages_callback)
38 incoming_messages_callback = NullObjectRtpFeedback();
39 return new RtpReceiverImpl(
40 id, clock, NullObjectRtpAudioFeedback(), incoming_messages_callback,
42 RTPReceiverStrategy::CreateVideoStrategy(id, incoming_payload_callback));
45 RtpReceiver* RtpReceiver::CreateAudioReceiver(
47 RtpAudioFeedback* incoming_audio_feedback,
48 RtpData* incoming_payload_callback,
49 RtpFeedback* incoming_messages_callback,
50 RTPPayloadRegistry* rtp_payload_registry) {
51 if (!incoming_audio_feedback)
52 incoming_audio_feedback = NullObjectRtpAudioFeedback();
53 if (!incoming_payload_callback)
54 incoming_payload_callback = NullObjectRtpData();
55 if (!incoming_messages_callback)
56 incoming_messages_callback = NullObjectRtpFeedback();
57 return new RtpReceiverImpl(
58 id, clock, incoming_audio_feedback, incoming_messages_callback,
60 RTPReceiverStrategy::CreateAudioStrategy(id, incoming_payload_callback,
61 incoming_audio_feedback));
64 RtpReceiverImpl::RtpReceiverImpl(int32_t id,
66 RtpAudioFeedback* incoming_audio_messages_callback,
67 RtpFeedback* incoming_messages_callback,
68 RTPPayloadRegistry* rtp_payload_registry,
69 RTPReceiverStrategy* rtp_media_receiver)
71 rtp_payload_registry_(rtp_payload_registry),
72 rtp_media_receiver_(rtp_media_receiver),
74 cb_rtp_feedback_(incoming_messages_callback),
75 critical_section_rtp_receiver_(
76 CriticalSectionWrapper::CreateCriticalSection()),
77 last_receive_time_(0),
78 last_received_payload_length_(0),
81 current_remote_csrc_(),
82 last_received_timestamp_(0),
83 last_received_frame_time_ms_(0),
84 last_received_sequence_number_(0),
85 nack_method_(kNackOff) {
86 assert(incoming_audio_messages_callback);
87 assert(incoming_messages_callback);
89 memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_));
91 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
94 RtpReceiverImpl::~RtpReceiverImpl() {
95 for (int i = 0; i < num_csrcs_; ++i) {
96 cb_rtp_feedback_->OnIncomingCSRCChanged(id_, current_remote_csrc_[i],
99 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id_, "%s deleted", __FUNCTION__);
102 RTPReceiverStrategy* RtpReceiverImpl::GetMediaReceiver() const {
103 return rtp_media_receiver_.get();
106 RtpVideoCodecTypes RtpReceiverImpl::VideoCodecType() const {
107 PayloadUnion media_specific;
108 rtp_media_receiver_->GetLastMediaSpecificPayload(&media_specific);
109 return media_specific.Video.videoCodecType;
112 int32_t RtpReceiverImpl::RegisterReceivePayload(
113 const char payload_name[RTP_PAYLOAD_NAME_SIZE],
114 const int8_t payload_type,
115 const uint32_t frequency,
116 const uint8_t channels,
117 const uint32_t rate) {
118 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
120 // TODO(phoglund): Try to streamline handling of the RED codec and some other
121 // cases which makes it necessary to keep track of whether we created a
123 bool created_new_payload = false;
124 int32_t result = rtp_payload_registry_->RegisterReceivePayload(
125 payload_name, payload_type, frequency, channels, rate,
126 &created_new_payload);
127 if (created_new_payload) {
128 if (rtp_media_receiver_->OnNewPayloadTypeCreated(payload_name, payload_type,
130 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
131 "%s failed to register payload",
139 int32_t RtpReceiverImpl::DeRegisterReceivePayload(
140 const int8_t payload_type) {
141 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
142 return rtp_payload_registry_->DeRegisterReceivePayload(payload_type);
145 NACKMethod RtpReceiverImpl::NACK() const {
146 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
150 // Turn negative acknowledgment requests on/off.
151 void RtpReceiverImpl::SetNACKStatus(const NACKMethod method) {
152 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
153 nack_method_ = method;
156 uint32_t RtpReceiverImpl::SSRC() const {
157 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
162 int32_t RtpReceiverImpl::CSRCs(uint32_t array_of_csrcs[kRtpCsrcSize]) const {
163 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
165 assert(num_csrcs_ <= kRtpCsrcSize);
167 if (num_csrcs_ > 0) {
168 memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t)*num_csrcs_);
173 int32_t RtpReceiverImpl::Energy(
174 uint8_t array_of_energy[kRtpCsrcSize]) const {
175 return rtp_media_receiver_->Energy(array_of_energy);
178 bool RtpReceiverImpl::IncomingRtpPacket(
179 const RTPHeader& rtp_header,
180 const uint8_t* payload,
182 PayloadUnion payload_specific,
185 if (payload_length < 0) {
186 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
187 "%s invalid argument",
191 int8_t first_payload_byte = 0;
192 if (payload_length > 0) {
193 first_payload_byte = payload[0];
195 // Trigger our callbacks.
196 CheckSSRCChanged(rtp_header);
199 bool should_reset_statistics = false;
201 if (CheckPayloadChanged(rtp_header,
205 &should_reset_statistics) == -1) {
206 if (payload_length == 0) {
207 // OK, keep-alive packet.
208 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_,
209 "%s received keepalive",
213 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
214 "%s received invalid payloadtype",
219 if (should_reset_statistics) {
220 cb_rtp_feedback_->ResetStatistics(ssrc_);
223 WebRtcRTPHeader webrtc_rtp_header;
224 memset(&webrtc_rtp_header, 0, sizeof(webrtc_rtp_header));
225 webrtc_rtp_header.header = rtp_header;
226 CheckCSRC(webrtc_rtp_header);
228 uint16_t payload_data_length = payload_length - rtp_header.paddingLength;
230 bool is_first_packet_in_frame = false;
231 bool is_first_packet = false;
233 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
234 is_first_packet_in_frame =
235 last_received_sequence_number_ + 1 == rtp_header.sequenceNumber &&
236 Timestamp() != rtp_header.timestamp;
237 is_first_packet = is_first_packet_in_frame || last_receive_time_ == 0;
240 int32_t ret_val = rtp_media_receiver_->ParseRtpPacket(
241 &webrtc_rtp_header, payload_specific, is_red, payload, payload_length,
242 clock_->TimeInMilliseconds(), is_first_packet);
249 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
251 last_receive_time_ = clock_->TimeInMilliseconds();
252 last_received_payload_length_ = payload_data_length;
255 if (last_received_timestamp_ != rtp_header.timestamp) {
256 last_received_timestamp_ = rtp_header.timestamp;
257 last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
259 last_received_sequence_number_ = rtp_header.sequenceNumber;
265 TelephoneEventHandler* RtpReceiverImpl::GetTelephoneEventHandler() {
266 return rtp_media_receiver_->GetTelephoneEventHandler();
269 uint32_t RtpReceiverImpl::Timestamp() const {
270 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
271 return last_received_timestamp_;
274 int32_t RtpReceiverImpl::LastReceivedTimeMs() const {
275 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
276 return last_received_frame_time_ms_;
279 // Implementation note: must not hold critsect when called.
280 void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader& rtp_header) {
281 bool new_ssrc = false;
282 bool re_initialize_decoder = false;
283 char payload_name[RTP_PAYLOAD_NAME_SIZE];
284 uint8_t channels = 1;
288 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
290 int8_t last_received_payload_type =
291 rtp_payload_registry_->last_received_payload_type();
292 if (ssrc_ != rtp_header.ssrc ||
293 (last_received_payload_type == -1 && ssrc_ == 0)) {
294 // We need the payload_type_ to make the call if the remote SSRC is 0.
297 cb_rtp_feedback_->ResetStatistics(ssrc_);
299 last_received_timestamp_ = 0;
300 last_received_sequence_number_ = 0;
301 last_received_frame_time_ms_ = 0;
303 // Do we have a SSRC? Then the stream is restarted.
305 // Do we have the same codec? Then re-initialize coder.
306 if (rtp_header.payloadType == last_received_payload_type) {
307 re_initialize_decoder = true;
310 if (!rtp_payload_registry_->PayloadTypeToPayload(
311 rtp_header.payloadType, payload)) {
315 payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
316 strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
317 if (payload->audio) {
318 channels = payload->typeSpecific.Audio.channels;
319 rate = payload->typeSpecific.Audio.rate;
323 ssrc_ = rtp_header.ssrc;
328 // We need to get this to our RTCP sender and receiver.
329 // We need to do this outside critical section.
330 cb_rtp_feedback_->OnIncomingSSRCChanged(id_, rtp_header.ssrc);
333 if (re_initialize_decoder) {
334 if (-1 == cb_rtp_feedback_->OnInitializeDecoder(
335 id_, rtp_header.payloadType, payload_name,
336 rtp_header.payload_type_frequency, channels, rate)) {
337 // New stream, same codec.
338 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
339 "Failed to create decoder for payload type:%d",
340 rtp_header.payloadType);
345 // Implementation note: must not hold critsect when called.
346 // TODO(phoglund): Move as much as possible of this code path into the media
347 // specific receivers. Basically this method goes through a lot of trouble to
348 // compute something which is only used by the media specific parts later. If
349 // this code path moves we can get rid of some of the rtp_receiver ->
350 // media_specific interface (such as CheckPayloadChange, possibly get/set
351 // last known payload).
352 int32_t RtpReceiverImpl::CheckPayloadChanged(
353 const RTPHeader& rtp_header,
354 const int8_t first_payload_byte,
356 PayloadUnion* specific_payload,
357 bool* should_reset_statistics) {
358 bool re_initialize_decoder = false;
360 char payload_name[RTP_PAYLOAD_NAME_SIZE];
361 int8_t payload_type = rtp_header.payloadType;
364 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
366 int8_t last_received_payload_type =
367 rtp_payload_registry_->last_received_payload_type();
368 // TODO(holmer): Remove this code when RED parsing has been broken out from
370 if (payload_type != last_received_payload_type) {
371 if (rtp_payload_registry_->red_payload_type() == payload_type) {
372 // Get the real codec payload type.
373 payload_type = first_payload_byte & 0x7f;
376 if (rtp_payload_registry_->red_payload_type() == payload_type) {
377 // Invalid payload type, traced by caller. If we proceeded here,
378 // this would be set as |_last_received_payload_type|, and we would no
379 // longer catch corrupt packets at this level.
383 // When we receive RED we need to check the real payload type.
384 if (payload_type == last_received_payload_type) {
385 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
389 *should_reset_statistics = false;
390 bool should_discard_changes = false;
392 rtp_media_receiver_->CheckPayloadChanged(
393 payload_type, specific_payload, should_reset_statistics,
394 &should_discard_changes);
396 if (should_discard_changes) {
402 if (!rtp_payload_registry_->PayloadTypeToPayload(payload_type, payload)) {
403 // Not a registered payload type.
407 payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
408 strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
410 rtp_payload_registry_->set_last_received_payload_type(payload_type);
412 re_initialize_decoder = true;
414 rtp_media_receiver_->SetLastMediaSpecificPayload(payload->typeSpecific);
415 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
417 if (!payload->audio) {
418 bool media_type_unchanged =
419 rtp_payload_registry_->ReportMediaPayloadType(payload_type);
420 if (media_type_unchanged) {
421 // Only reset the decoder if the media codec type has changed.
422 re_initialize_decoder = false;
425 if (re_initialize_decoder) {
426 *should_reset_statistics = true;
429 rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload);
434 if (re_initialize_decoder) {
435 if (-1 == rtp_media_receiver_->InvokeOnInitializeDecoder(
436 cb_rtp_feedback_, id_, payload_type, payload_name,
437 *specific_payload)) {
438 return -1; // Wrong payload type.
444 // Implementation note: must not hold critsect when called.
445 void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) {
446 int32_t num_csrcs_diff = 0;
447 uint32_t old_remote_csrc[kRtpCsrcSize];
448 uint8_t old_num_csrcs = 0;
451 CriticalSectionScoped lock(critical_section_rtp_receiver_.get());
453 if (!rtp_media_receiver_->ShouldReportCsrcChanges(
454 rtp_header.header.payloadType)) {
457 old_num_csrcs = num_csrcs_;
458 if (old_num_csrcs > 0) {
459 // Make a copy of old.
460 memcpy(old_remote_csrc, current_remote_csrc_,
461 num_csrcs_ * sizeof(uint32_t));
463 const uint8_t num_csrcs = rtp_header.header.numCSRCs;
464 if ((num_csrcs > 0) && (num_csrcs <= kRtpCsrcSize)) {
466 memcpy(current_remote_csrc_,
467 rtp_header.header.arrOfCSRCs,
468 num_csrcs * sizeof(uint32_t));
470 if (num_csrcs > 0 || old_num_csrcs > 0) {
471 num_csrcs_diff = num_csrcs - old_num_csrcs;
472 num_csrcs_ = num_csrcs; // Update stored CSRCs.
479 bool have_called_callback = false;
480 // Search for new CSRC in old array.
481 for (uint8_t i = 0; i < rtp_header.header.numCSRCs; ++i) {
482 const uint32_t csrc = rtp_header.header.arrOfCSRCs[i];
484 bool found_match = false;
485 for (uint8_t j = 0; j < old_num_csrcs; ++j) {
486 if (csrc == old_remote_csrc[j]) { // old list
491 if (!found_match && csrc) {
492 // Didn't find it, report it as new.
493 have_called_callback = true;
494 cb_rtp_feedback_->OnIncomingCSRCChanged(id_, csrc, true);
497 // Search for old CSRC in new array.
498 for (uint8_t i = 0; i < old_num_csrcs; ++i) {
499 const uint32_t csrc = old_remote_csrc[i];
501 bool found_match = false;
502 for (uint8_t j = 0; j < rtp_header.header.numCSRCs; ++j) {
503 if (csrc == rtp_header.header.arrOfCSRCs[j]) {
508 if (!found_match && csrc) {
509 // Did not find it, report as removed.
510 have_called_callback = true;
511 cb_rtp_feedback_->OnIncomingCSRCChanged(id_, csrc, false);
514 if (!have_called_callback) {
515 // If the CSRC list contain non-unique entries we will end up here.
516 // Using CSRC 0 to signal this event, not interop safe, other
517 // implementations might have CSRC 0 as a valid value.
518 if (num_csrcs_diff > 0) {
519 cb_rtp_feedback_->OnIncomingCSRCChanged(id_, 0, true);
520 } else if (num_csrcs_diff < 0) {
521 cb_rtp_feedback_->OnIncomingCSRCChanged(id_, 0, false);
526 } // namespace webrtc