diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc new file mode 100644 index 0000000000..2275d14a1d --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2012 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 "webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h" + +#include "webrtc/system_wrappers/interface/trace.h" + +namespace webrtc { + +RTPPayloadRegistry::RTPPayloadRegistry( + const WebRtc_Word32 id) + : id_(id), + rtp_media_receiver_(NULL), + red_payload_type_(-1), + last_received_payload_type_(-1), + last_received_media_payload_type_(-1) { +} + +RTPPayloadRegistry::~RTPPayloadRegistry() { + while (!payload_type_map_.empty()) { + ModuleRTPUtility::PayloadTypeMap::iterator it = payload_type_map_.begin(); + delete it->second; + payload_type_map_.erase(it); + } +} + +WebRtc_Word32 RTPPayloadRegistry::RegisterReceivePayload( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_Word8 payload_type, + const WebRtc_UWord32 frequency, + const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate) { + assert(rtp_media_receiver_); + assert(payload_name); + + // Sanity check. + switch (payload_type) { + // Reserved payload types to avoid RTCP conflicts when marker bit is set. + case 64: // 192 Full INTRA-frame request. + case 72: // 200 Sender report. + case 73: // 201 Receiver report. + case 74: // 202 Source description. + case 75: // 203 Goodbye. + case 76: // 204 Application-defined. + case 77: // 205 Transport layer FB message. + case 78: // 206 Payload-specific FB message. + case 79: // 207 Extended report. + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, + "%s invalid payloadtype:%d", + __FUNCTION__, payload_type); + return -1; + default: + break; + } + size_t payload_name_length = strlen(payload_name); + + ModuleRTPUtility::PayloadTypeMap::iterator it = + payload_type_map_.find(payload_type); + + if (it != payload_type_map_.end()) { + // We already use this payload type. + ModuleRTPUtility::Payload* payload = it->second; + assert(payload); + + size_t name_length = strlen(payload->name); + + // Check if it's the same as we already have. + // If same, ignore sending an error. + if (payload_name_length == name_length && + ModuleRTPUtility::StringCompare( + payload->name, payload_name, payload_name_length)) { + if (rtp_media_receiver_->PayloadIsCompatible(*payload, frequency, + channels, rate)) { + rtp_media_receiver_->UpdatePayloadRate(payload, rate); + return 0; + } + } + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, + "%s invalid argument payload_type:%d already registered", + __FUNCTION__, payload_type); + return -1; + } + + rtp_media_receiver_->PossiblyRemoveExistingPayloadType( + &payload_type_map_, payload_name, payload_name_length, frequency, channels, + rate); + + ModuleRTPUtility::Payload* payload = NULL; + + // Save the RED payload type. Used in both audio and video. + if (ModuleRTPUtility::StringCompare(payload_name, "red", 3)) { + red_payload_type_ = payload_type; + payload = new ModuleRTPUtility::Payload; + payload->audio = false; + payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; + strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); + } else { + payload = rtp_media_receiver_->CreatePayloadType( + payload_name, payload_type, frequency, channels, rate); + } + if (payload == NULL) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, + "%s failed to register payload", + __FUNCTION__); + return -1; + } + payload_type_map_[payload_type] = payload; + + // Successful set of payload type, clear the value of last received payload + // type since it might mean something else. + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; + return 0; +} + +WebRtc_Word32 RTPPayloadRegistry::DeRegisterReceivePayload( + const WebRtc_Word8 payload_type) { + assert(rtp_media_receiver_); + ModuleRTPUtility::PayloadTypeMap::iterator it = + payload_type_map_.find(payload_type); + + if (it == payload_type_map_.end()) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, + "%s failed to find payload_type:%d", + __FUNCTION__, payload_type); + return -1; + } + delete it->second; + payload_type_map_.erase(it); + return 0; +} + +WebRtc_Word32 RTPPayloadRegistry::ReceivePayloadType( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_UWord32 frequency, + const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate, + WebRtc_Word8* payload_type) const { + if (payload_type == NULL) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, + "%s invalid argument", __FUNCTION__); + return -1; + } + size_t payload_name_length = strlen(payload_name); + + ModuleRTPUtility::PayloadTypeMap::const_iterator it = + payload_type_map_.begin(); + + while (it != payload_type_map_.end()) { + ModuleRTPUtility::Payload* payload = it->second; + assert(payload); + + size_t name_length = strlen(payload->name); + if (payload_name_length == name_length && + ModuleRTPUtility::StringCompare( + payload->name, payload_name, payload_name_length)) { + // Name matches. + if (payload->audio) { + if (rate == 0) { + // [default] audio, check freq and channels. + if (payload->typeSpecific.Audio.frequency == frequency && + payload->typeSpecific.Audio.channels == channels) { + *payload_type = it->first; + return 0; + } + } else { + // Non-default audio, check freq, channels and rate. + if (payload->typeSpecific.Audio.frequency == frequency && + payload->typeSpecific.Audio.channels == channels && + payload->typeSpecific.Audio.rate == rate) { + // extra rate condition added + *payload_type = it->first; + return 0; + } + } + } else { + // Video. + *payload_type = it->first; + return 0; + } + } + it++; + } + return -1; +} + +WebRtc_Word32 RTPPayloadRegistry::ReceivePayload( + const WebRtc_Word8 payload_type, + char payload_name[RTP_PAYLOAD_NAME_SIZE], + WebRtc_UWord32* frequency, + WebRtc_UWord8* channels, + WebRtc_UWord32* rate) const { + assert(rtp_media_receiver_); + ModuleRTPUtility::PayloadTypeMap::const_iterator it = + payload_type_map_.find(payload_type); + + if (it == payload_type_map_.end()) { + return -1; + } + ModuleRTPUtility::Payload* payload = it->second; + assert(payload); + + if (frequency) { + if (payload->audio) { + *frequency = payload->typeSpecific.Audio.frequency; + } else { + *frequency = kDefaultVideoFrequency; + } + } + if (channels) { + if (payload->audio) { + *channels = payload->typeSpecific.Audio.channels; + } else { + *channels = 1; + } + } + if (rate) { + if (payload->audio) { + *rate = payload->typeSpecific.Audio.rate; + } else { + assert(false); + *rate = 0; + } + } + if (payload_name) { + payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; + strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); + } + return 0; +} + +WebRtc_UWord32 RTPPayloadRegistry::PayloadTypeToPayload( + const WebRtc_UWord8 payload_type, + ModuleRTPUtility::Payload*& payload) const { + assert(rtp_media_receiver_); + + ModuleRTPUtility::PayloadTypeMap::const_iterator it = + payload_type_map_.find(payload_type); + + // Check that this is a registered payload type. + if (it == payload_type_map_.end()) { + return -1; + } + payload = it->second; + return 0; +} + +bool RTPPayloadRegistry::ReportMediaPayloadType( + WebRtc_UWord8 media_payload_type) { + if (last_received_media_payload_type_ == media_payload_type) { + // Media type unchanged. + return true; + } + last_received_media_payload_type_ = media_payload_type; + return false; +} + +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h new file mode 100644 index 0000000000..888de38bc3 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012 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. + */ + +#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PAYLOAD_REGISTRY_H_ +#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PAYLOAD_REGISTRY_H_ + +#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" + +namespace webrtc { + +class RTPPayloadRegistry { + public: + explicit RTPPayloadRegistry(const WebRtc_Word32 id); + ~RTPPayloadRegistry(); + + // Must be called before any other methods are used! + // TODO(phoglund): We shouldn't really have to talk to a media receiver here. + // It would make more sense to talk to some media-specific payload handling + // strategy. Can't do that right now because audio payload type handling is + // too tightly coupled with packet parsing. + void set_rtp_media_receiver(RTPReceiverStrategy* rtp_media_receiver) { + rtp_media_receiver_ = rtp_media_receiver; + } + + WebRtc_Word32 RegisterReceivePayload( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_Word8 payload_type, + const WebRtc_UWord32 frequency, + const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate); + + WebRtc_Word32 DeRegisterReceivePayload( + const WebRtc_Word8 payload_type); + + WebRtc_Word32 ReceivePayloadType( + const char payload_name[RTP_PAYLOAD_NAME_SIZE], + const WebRtc_UWord32 frequency, + const WebRtc_UWord8 channels, + const WebRtc_UWord32 rate, + WebRtc_Word8* payload_type) const; + + WebRtc_Word32 ReceivePayload( + const WebRtc_Word8 payload_type, + char payload_name[RTP_PAYLOAD_NAME_SIZE], + WebRtc_UWord32* frequency, + WebRtc_UWord8* channels, + WebRtc_UWord32* rate) const; + + WebRtc_UWord32 PayloadTypeToPayload( + const WebRtc_UWord8 payload_type, + ModuleRTPUtility::Payload*& payload) const; + + void ResetLastReceivedPayloadTypes() { + last_received_payload_type_ = -1; + last_received_media_payload_type_ = -1; + } + + // Returns true if the new media payload type has not changed. + bool ReportMediaPayloadType(WebRtc_UWord8 media_payload_type); + + WebRtc_Word8 red_payload_type() const { return red_payload_type_; } + WebRtc_Word8 last_received_payload_type() const { + return last_received_payload_type_; + } + void set_last_received_payload_type(WebRtc_Word8 last_received_payload_type) { + last_received_payload_type_ = last_received_payload_type; + } + + private: + ModuleRTPUtility::PayloadTypeMap payload_type_map_; + WebRtc_Word32 id_; + RTPReceiverStrategy* rtp_media_receiver_; + WebRtc_Word8 red_payload_type_; + WebRtc_Word8 last_received_payload_type_; + WebRtc_Word8 last_received_media_payload_type_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_PAYLOAD_REGISTRY_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc index 32a216e472..8132af115c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc @@ -39,6 +39,7 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id, RtpData* incoming_payload_callback, RtpFeedback* incoming_messages_callback) : Bitrate(clock), + rtp_payload_registry_(id), // TODO(phoglund): Remove hacks requiring direct access to the // audio receiver and only instantiate one of these directly into the // rtp_media_receiver_ field. Right now an audio receiver carries around a @@ -46,7 +47,7 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id, rtp_receiver_audio_(new RTPReceiverAudio( id, incoming_payload_callback, incoming_audio_messages_callback)), rtp_receiver_video_(new RTPReceiverVideo( - id, this, incoming_payload_callback, owner)), + id, &rtp_payload_registry_, incoming_payload_callback, owner)), id_(id), rtp_rtcp_(*owner), cb_rtp_feedback_(incoming_messages_callback), @@ -55,13 +56,9 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id, CriticalSectionWrapper::CreateCriticalSection()), last_receive_time_(0), last_received_payload_length_(0), - last_received_payload_type_(-1), - last_received_media_payload_type_(-1), packet_timeout_ms_(0), - red_payload_type_(-1), - payload_type_map_(), rtp_header_extension_map_(), ssrc_(0), num_csrcs_(0), @@ -105,11 +102,15 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id, assert(incoming_audio_messages_callback && incoming_messages_callback && incoming_payload_callback); + if (audio) { - rtp_media_receiver_ = rtp_receiver_audio_; + rtp_media_receiver_ = rtp_receiver_audio_.get(); } else { - rtp_media_receiver_ = rtp_receiver_video_; + rtp_media_receiver_ = rtp_receiver_video_.get(); } + // TODO(phoglund): Get rid of this silly circular dependency between the + // payload manager and the video RTP receiver. + rtp_payload_registry_.set_rtp_media_receiver(rtp_media_receiver_); memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_)); memset(current_remote_energy_, 0, sizeof(current_remote_energy_)); @@ -123,14 +124,6 @@ RTPReceiver::~RTPReceiver() { false); } delete critical_section_rtp_receiver_; - - while (!payload_type_map_.empty()) { - std::map::iterator it = payload_type_map_.begin(); - delete it->second; - payload_type_map_.erase(it); - } - delete rtp_receiver_video_; - delete rtp_receiver_audio_; WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id_, "%s deleted", __FUNCTION__); } @@ -147,11 +140,11 @@ WebRtc_UWord32 RTPReceiver::MaxConfiguredBitrate() const { } bool RTPReceiver::REDPayloadType(const WebRtc_Word8 payload_type) const { - return (red_payload_type_ == payload_type) ? true : false; + return rtp_payload_registry_.red_payload_type() == payload_type; } WebRtc_Word8 RTPReceiver::REDPayloadType() const { - return red_payload_type_; + return rtp_payload_registry_.red_payload_type(); } WebRtc_Word32 RTPReceiver::SetPacketTimeout(const WebRtc_UWord32 timeout_ms) { @@ -183,8 +176,7 @@ void RTPReceiver::PacketTimeout() { if (now - last_receive_time_ > packet_timeout_ms_) { packet_time_out = true; last_receive_time_ = 0; // Only one callback. - last_received_payload_type_ = -1; // Makes RemotePayload return -1. - last_received_media_payload_type_ = -1; + rtp_payload_registry_.ResetLastReceivedPayloadTypes(); } } if (packet_time_out) { @@ -233,104 +225,15 @@ WebRtc_Word32 RTPReceiver::RegisterReceivePayload( const WebRtc_UWord32 frequency, const WebRtc_UWord8 channels, const WebRtc_UWord32 rate) { - assert(payload_name); CriticalSectionScoped lock(critical_section_rtp_receiver_); - - // Sanity check. - switch (payload_type) { - // Reserved payload types to avoid RTCP conflicts when marker bit is set. - case 64: // 192 Full INTRA-frame request. - case 72: // 200 Sender report. - case 73: // 201 Receiver report. - case 74: // 202 Source description. - case 75: // 203 Goodbye. - case 76: // 204 Application-defined. - case 77: // 205 Transport layer FB message. - case 78: // 206 Payload-specific FB message. - case 79: // 207 Extended report. - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, - "%s invalid payloadtype:%d", - __FUNCTION__, payload_type); - return -1; - default: - break; - } - size_t payload_name_length = strlen(payload_name); - - std::map::iterator it = - payload_type_map_.find(payload_type); - - if (it != payload_type_map_.end()) { - // We already use this payload type. - Payload* payload = it->second; - assert(payload); - - size_t name_length = strlen(payload->name); - - // Check if it's the same as we already have. - // If same, ignore sending an error. - if (payload_name_length == name_length && - StringCompare(payload->name, payload_name, payload_name_length)) { - if (rtp_media_receiver_->PayloadIsCompatible(*payload, frequency, - channels, rate)) { - rtp_media_receiver_->UpdatePayloadRate(payload, rate); - return 0; - } - } - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, - "%s invalid argument payload_type:%d already registered", - __FUNCTION__, payload_type); - return -1; - } - - rtp_media_receiver_->PossiblyRemoveExistingPayloadType( - &payload_type_map_, payload_name, payload_name_length, frequency, channels, - rate); - - Payload* payload = NULL; - - // Save the RED payload type. Used in both audio and video. - if (StringCompare(payload_name, "red", 3)) { - red_payload_type_ = payload_type; - payload = new Payload; - payload->audio = false; - payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; - strncpy(payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1); - } else { - payload = rtp_media_receiver_->CreatePayloadType( - payload_name, payload_type, frequency, channels, rate); - } - if (payload == NULL) { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, - "%s failed to register payload", - __FUNCTION__); - return -1; - } - payload_type_map_[payload_type] = payload; - - // Successful set of payload type, clear the value of last received payload - // type since it might mean something else. - last_received_payload_type_ = -1; - last_received_media_payload_type_ = -1; - return 0; + return rtp_payload_registry_.RegisterReceivePayload( + payload_name, payload_type, frequency, channels, rate); } WebRtc_Word32 RTPReceiver::DeRegisterReceivePayload( const WebRtc_Word8 payload_type) { CriticalSectionScoped lock(critical_section_rtp_receiver_); - - std::map::iterator it = - payload_type_map_.find(payload_type); - - if (it == payload_type_map_.end()) { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, - "%s failed to find payload_type:%d", - __FUNCTION__, payload_type); - return -1; - } - delete it->second; - payload_type_map_.erase(it); - return 0; + return rtp_payload_registry_.DeRegisterReceivePayload(payload_type); } WebRtc_Word32 RTPReceiver::ReceivePayloadType( @@ -339,53 +242,9 @@ WebRtc_Word32 RTPReceiver::ReceivePayloadType( const WebRtc_UWord8 channels, const WebRtc_UWord32 rate, WebRtc_Word8* payload_type) const { - if (payload_type == NULL) { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_, - "%s invalid argument", __FUNCTION__); - return -1; - } - size_t payload_name_length = strlen(payload_name); - CriticalSectionScoped lock(critical_section_rtp_receiver_); - - std::map::const_iterator it = - payload_type_map_.begin(); - - while (it != payload_type_map_.end()) { - Payload* payload = it->second; - assert(payload); - - size_t name_length = strlen(payload->name); - if (payload_name_length == name_length && - StringCompare(payload->name, payload_name, payload_name_length)) { - // Name matches. - if (payload->audio) { - if (rate == 0) { - // [default] audio, check freq and channels. - if (payload->typeSpecific.Audio.frequency == frequency && - payload->typeSpecific.Audio.channels == channels) { - *payload_type = it->first; - return 0; - } - } else { - // Non-default audio, check freq, channels and rate. - if (payload->typeSpecific.Audio.frequency == frequency && - payload->typeSpecific.Audio.channels == channels && - payload->typeSpecific.Audio.rate == rate) { - // extra rate condition added - *payload_type = it->first; - return 0; - } - } - } else { - // Video. - *payload_type = it->first; - return 0; - } - } - it++; - } - return -1; + return rtp_payload_registry_.ReceivePayloadType( + payload_name, frequency, channels, rate, payload_type); } WebRtc_Word32 RTPReceiver::ReceivePayload( @@ -395,84 +254,8 @@ WebRtc_Word32 RTPReceiver::ReceivePayload( WebRtc_UWord8* channels, WebRtc_UWord32* rate) const { CriticalSectionScoped lock(critical_section_rtp_receiver_); - - std::map::const_iterator it = - payload_type_map_.find(payload_type); - - if (it == payload_type_map_.end()) { - return -1; - } - Payload* payload = it->second; - assert(payload); - - if (frequency) { - if (payload->audio) { - *frequency = payload->typeSpecific.Audio.frequency; - } else { - *frequency = kDefaultVideoFrequency; - } - } - if (channels) { - if (payload->audio) { - *channels = payload->typeSpecific.Audio.channels; - } else { - *channels = 1; - } - } - if (rate) { - if (payload->audio) { - *rate = payload->typeSpecific.Audio.rate; - } else { - assert(false); - *rate = 0; - } - } - if (payload_name) { - payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; - strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); - } - return 0; -} - -WebRtc_Word32 RTPReceiver::RemotePayload( - char payload_name[RTP_PAYLOAD_NAME_SIZE], - WebRtc_Word8* payload_type, - WebRtc_UWord32* frequency, - WebRtc_UWord8* channels) const { - if (last_received_payload_type_ == -1) { - WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_, - "%s invalid state", __FUNCTION__); - return -1; - } - std::map::const_iterator it = - payload_type_map_.find(last_received_payload_type_); - - if (it == payload_type_map_.end()) { - return -1; - } - Payload* payload = it->second; - assert(payload); - payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; - strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); - - if (payload_type) { - *payload_type = last_received_payload_type_; - } - if (frequency) { - if (payload->audio) { - *frequency = payload->typeSpecific.Audio.frequency; - } else { - *frequency = kDefaultVideoFrequency; - } - } - if (channels) { - if (payload->audio) { - *channels = payload->typeSpecific.Audio.channels; - } else { - *channels = 1; - } - } - return 0; + return rtp_payload_registry_.ReceivePayload( + payload_type, payload_name, frequency, channels, rate); } WebRtc_Word32 RTPReceiver::RegisterRtpHeaderExtension( @@ -626,9 +409,14 @@ WebRtc_Word32 RTPReceiver::IncomingRTPPacket( WebRtc_UWord16 payload_data_length = ModuleRTPUtility::GetPayloadDataLength(rtp_header, packet_length); + bool is_first_packet_in_frame = + SequenceNumber() + 1 == rtp_header->header.sequenceNumber && + TimeStamp() != rtp_header->header.timestamp; + bool is_first_packet = is_first_packet_in_frame || HaveNotReceivedPackets(); + WebRtc_Word32 ret_val = rtp_media_receiver_->ParseRtpPacket( - rtp_header, specific_payload, is_red, packet, - packet_length, clock_.TimeInMilliseconds()); + rtp_header, specific_payload, is_red, packet, packet_length, + clock_.TimeInMilliseconds(), is_first_packet); if (ret_val < 0) { return ret_val; @@ -835,18 +623,10 @@ int32_t RTPReceiver::LastReceivedTimeMs() const { } WebRtc_UWord32 RTPReceiver::PayloadTypeToPayload( - const WebRtc_UWord8 payload_type, - Payload*& payload) const { - - std::map::const_iterator it = - payload_type_map_.find(payload_type); - - // Check that this is a registered payload type. - if (it == payload_type_map_.end()) { - return -1; - } - payload = it->second; - return 0; + const WebRtc_UWord8 payload_type, + Payload*& payload) const { + CriticalSectionScoped lock(critical_section_rtp_receiver_); + return rtp_payload_registry_.PayloadTypeToPayload(payload_type, payload); } // Compute time stamp of the last incoming packet that is the first packet of @@ -907,8 +687,10 @@ void RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtp_header) { { CriticalSectionScoped lock(critical_section_rtp_receiver_); + WebRtc_Word8 last_received_payload_type = + rtp_payload_registry_.last_received_payload_type(); if (ssrc_ != rtp_header->header.ssrc || - (last_received_payload_type_ == -1 && ssrc_ == 0)) { + (last_received_payload_type == -1 && ssrc_ == 0)) { // We need the payload_type_ to make the call if the remote SSRC is 0. new_ssrc = true; @@ -922,16 +704,14 @@ void RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtp_header) { // Do we have a SSRC? Then the stream is restarted. if (ssrc_) { // Do we have the same codec? Then re-initialize coder. - if (rtp_header->header.payloadType == last_received_payload_type_) { + if (rtp_header->header.payloadType == last_received_payload_type) { re_initialize_decoder = true; - std::map::iterator it = - payload_type_map_.find(rtp_header->header.payloadType); - - if (it == payload_type_map_.end()) { + Payload* payload; + if (rtp_payload_registry_.PayloadTypeToPayload( + rtp_header->header.payloadType, payload) != 0) { return; } - Payload* payload = it->second; assert(payload); payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); @@ -985,7 +765,9 @@ WebRtc_Word32 RTPReceiver::CheckPayloadChanged( { CriticalSectionScoped lock(critical_section_rtp_receiver_); - if (payload_type != last_received_payload_type_) { + WebRtc_Word8 last_received_payload_type = + rtp_payload_registry_.last_received_payload_type(); + if (payload_type != last_received_payload_type) { if (REDPayloadType(payload_type)) { // Get the real codec payload type. payload_type = first_payload_byte & 0x7f; @@ -999,7 +781,7 @@ WebRtc_Word32 RTPReceiver::CheckPayloadChanged( } // When we receive RED we need to check the real payload type. - if (payload_type == last_received_payload_type_) { + if (payload_type == last_received_payload_type) { rtp_media_receiver_->GetLastMediaSpecificPayload(specific_payload); return 0; } @@ -1019,19 +801,17 @@ WebRtc_Word32 RTPReceiver::CheckPayloadChanged( return 0; } - std::map::iterator it = - payload_type_map_.find(payload_type); - - // Check that this is a registered payload type. - if (it == payload_type_map_.end()) { + Payload* payload; + if (rtp_payload_registry_.PayloadTypeToPayload(payload_type, + payload) != 0) { + // Not a registered payload type. return -1; } - Payload* payload = it->second; assert(payload); payload_name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; strncpy(payload_name, payload->name, RTP_PAYLOAD_NAME_SIZE - 1); - last_received_payload_type_ = payload_type; + rtp_payload_registry_.set_last_received_payload_type(payload_type); re_initialize_decoder = true; @@ -1043,12 +823,12 @@ WebRtc_Word32 RTPReceiver::CheckPayloadChanged( // Only reset the decoder on media packets. re_initialize_decoder = false; } else { - if (last_received_media_payload_type_ == - last_received_payload_type_) { + bool media_type_unchanged = + rtp_payload_registry_.ReportMediaPayloadType(payload_type); + if (media_type_unchanged) { // Only reset the decoder if the media codec type has changed. re_initialize_decoder = false; } - last_received_media_payload_type_ = last_received_payload_type_; } } if (re_initialize_decoder) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver.h index 81a6dd7bf4..00fb6d9125 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver.h @@ -18,7 +18,9 @@ #include "webrtc/modules/rtp_rtcp/source/bitrate.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -76,11 +78,6 @@ class RTPReceiver : public Bitrate { WebRtc_UWord8* channels, WebRtc_UWord32* rate) const; - WebRtc_Word32 RemotePayload(char payload_name[RTP_PAYLOAD_NAME_SIZE], - WebRtc_Word8* payload_type, - WebRtc_UWord32* frequency, - WebRtc_UWord8* channels) const; - WebRtc_Word32 IncomingRTPPacket( WebRtcRTPHeader* rtpheader, const WebRtc_UWord8* incoming_rtp_packet, @@ -158,7 +155,7 @@ class RTPReceiver : public Bitrate { void RTXStatus(bool* enable, WebRtc_UWord32* ssrc) const; RTPReceiverAudio* GetAudioReceiver() const { - return rtp_receiver_audio_; + return rtp_receiver_audio_.get(); } virtual WebRtc_Word8 REDPayloadType() const; @@ -190,9 +187,10 @@ class RTPReceiver : public Bitrate { bool ProcessNACKBitRate(WebRtc_UWord32 now); private: - RTPReceiverAudio* rtp_receiver_audio_; - RTPReceiverVideo* rtp_receiver_video_; - RTPReceiverStrategy* rtp_media_receiver_; + RTPPayloadRegistry rtp_payload_registry_; + scoped_ptr rtp_receiver_audio_; + scoped_ptr rtp_receiver_video_; + RTPReceiverStrategy* rtp_media_receiver_; WebRtc_Word32 id_; ModuleRtpRtcpImpl& rtp_rtcp_; @@ -202,14 +200,10 @@ class RTPReceiver : public Bitrate { CriticalSectionWrapper* critical_section_rtp_receiver_; mutable WebRtc_Word64 last_receive_time_; WebRtc_UWord16 last_received_payload_length_; - WebRtc_Word8 last_received_payload_type_; - WebRtc_Word8 last_received_media_payload_type_; WebRtc_UWord32 packet_timeout_ms_; - WebRtc_Word8 red_payload_type_; - ModuleRTPUtility::PayloadTypeMap payload_type_map_; - RtpHeaderExtensionMap rtp_header_extension_map_; + RtpHeaderExtensionMap rtp_header_extension_map_; // SSRCs. WebRtc_UWord32 ssrc_; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc index 71d8a2bf13..b4a51d31ab 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.cc @@ -255,7 +255,8 @@ WebRtc_Word32 RTPReceiverAudio::ParseRtpPacket( const bool isRed, const WebRtc_UWord8* packet, const WebRtc_UWord16 packetLength, - const WebRtc_Word64 timestampMs) { + const WebRtc_Word64 timestampMs, + const bool isFirstPacket) { const WebRtc_UWord8* payloadData = ModuleRTPUtility::GetPayloadData(rtpHeader, packet); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h index f4b294206a..173966cc5d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h @@ -59,7 +59,8 @@ public: const bool isRed, const WebRtc_UWord8* packet, const WebRtc_UWord16 packetLength, - const WebRtc_Word64 timestampMs); + const WebRtc_Word64 timestampMs, + const bool isFirstPacket); WebRtc_Word32 GetFrequencyHz() const; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h index fc553c0149..7ceed594d9 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h @@ -37,14 +37,16 @@ class RTPReceiverStrategy { // Implementations are encouraged to use the provided packet buffer and RTP // header as arguments to the callback; implementations are also allowed to // make changes in the data as necessary. The specific_payload argument - // provides audio or video-specific data. + // provides audio or video-specific data. The is_first_packet argument is true + // if this packet is either the first packet ever or the first in its frame. virtual WebRtc_Word32 ParseRtpPacket( WebRtcRTPHeader* rtp_header, const ModuleRTPUtility::PayloadUnion& specific_payload, const bool is_red, const WebRtc_UWord8* packet, const WebRtc_UWord16 packet_length, - const WebRtc_Word64 timestamp_ms) = 0; + const WebRtc_Word64 timestamp_ms, + const bool is_first_packet) = 0; // Retrieves the last known applicable frequency. virtual WebRtc_Word32 GetFrequencyHz() const = 0; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc index a3fafe5e87..65cff671db 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.cc @@ -16,7 +16,7 @@ #include "critical_section_wrapper.h" #include "receiver_fec.h" -#include "rtp_receiver.h" +#include "rtp_payload_registry.h" #include "rtp_rtcp_impl.h" #include "rtp_utility.h" #include "trace.h" @@ -27,13 +27,14 @@ WebRtc_UWord32 BitRateBPS(WebRtc_UWord16 x ) return (x & 0x3fff) * WebRtc_UWord32(pow(10.0f,(2 + (x >> 14)))); } -RTPReceiverVideo::RTPReceiverVideo(const WebRtc_Word32 id, - RTPReceiver* parent, - RtpData* data_callback, - ModuleRtpRtcpImpl* owner) +RTPReceiverVideo::RTPReceiverVideo( + const WebRtc_Word32 id, + const RTPPayloadRegistry* rtpRtpPayloadRegistry, + RtpData* data_callback, + ModuleRtpRtcpImpl* owner) : RTPReceiverStrategy(data_callback), _id(id), - _parent(parent), + _rtpRtpPayloadRegistry(rtpRtpPayloadRegistry), _criticalSectionReceiverVideo( CriticalSectionWrapper::CreateCriticalSection()), _currentFecFrameDecoded(false), @@ -82,7 +83,8 @@ WebRtc_Word32 RTPReceiverVideo::ParseRtpPacket( const bool isRed, const WebRtc_UWord8* packet, const WebRtc_UWord16 packetLength, - const WebRtc_Word64 timestampMs) { + const WebRtc_Word64 timestampMs, + const bool isFirstPacket) { const WebRtc_UWord8* payloadData = ModuleRTPUtility::GetPayloadData(rtpHeader, packet); const WebRtc_UWord16 payloadDataLength = @@ -90,7 +92,7 @@ WebRtc_Word32 RTPReceiverVideo::ParseRtpPacket( return ParseVideoCodecSpecific( rtpHeader, payloadData, payloadDataLength, specificPayload.Video.videoCodecType, isRed, packet, packetLength, - timestampMs); + timestampMs, isFirstPacket); } WebRtc_Word32 RTPReceiverVideo::GetFrequencyHz() const { @@ -144,7 +146,8 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecific( const bool isRED, const WebRtc_UWord8* incomingRtpPacket, const WebRtc_UWord16 incomingRtpPacketSize, - const WebRtc_Word64 nowMS) { + const WebRtc_Word64 nowMS, + const bool isFirstPacket) { WebRtc_Word32 retVal = 0; _criticalSectionReceiverVideo->Enter(); @@ -186,7 +189,8 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecific( retVal = ParseVideoCodecSpecificSwitch(rtpHeader, payloadData, payloadDataLength, - videoType); + videoType, + isFirstPacket); } return retVal; } @@ -237,7 +241,7 @@ WebRtc_Word32 RTPReceiverVideo::ReceiveRecoveredPacketCallback( _currentFecFrameDecoded = true; ModuleRTPUtility::Payload* payload = NULL; - if (_parent->PayloadTypeToPayload( + if (_rtpRtpPayloadRegistry->PayloadTypeToPayload( rtpHeader->header.payloadType, payload) != 0) { _criticalSectionReceiverVideo->Leave(); return -1; @@ -252,7 +256,7 @@ WebRtc_Word32 RTPReceiverVideo::ReceiveRecoveredPacketCallback( // replace pltype recoveredPacket[1] &= 0x80; // Reset. - recoveredPacket[1] += _parent->REDPayloadType(); + recoveredPacket[1] += _rtpRtpPayloadRegistry->red_payload_type(); // add RED header recoveredPacket[rtpHeaderLength] = rtpHeader->header.payloadType; @@ -261,11 +265,17 @@ WebRtc_Word32 RTPReceiverVideo::ReceiveRecoveredPacketCallback( memcpy(recoveredPacket + rtpHeaderLength + REDForFECHeaderLength, payloadData, payloadDataLength); + // A recovered packet can be the first packet, but we lack the ability to + // detect it at the moment since we do not store the history of recently + // received packets. Most codecs like VP8 deal with this in other ways. + bool isFirstPacket = false; + return ParseVideoCodecSpecificSwitch( rtpHeader, payloadData, payloadDataLength, - payload->typeSpecific.Video.videoCodecType); + payload->typeSpecific.Video.videoCodecType, + isFirstPacket); } WebRtc_Word32 RTPReceiverVideo::SetCodecType(const RtpVideoCodecTypes videoType, @@ -288,7 +298,8 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecificSwitch( WebRtcRTPHeader* rtpHeader, const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadDataLength, - const RtpVideoCodecTypes videoType) { + const RtpVideoCodecTypes videoType, + const bool isFirstPacket) { WebRtc_Word32 retVal = SetCodecType(videoType, rtpHeader); if (retVal != 0) { _criticalSectionReceiverVideo->Leave(); @@ -301,6 +312,7 @@ WebRtc_Word32 RTPReceiverVideo::ParseVideoCodecSpecificSwitch( // returning. switch (videoType) { case kRtpNoVideo: + rtpHeader->type.Video.isFirstPacket = isFirstPacket; return ReceiveGenericCodec(rtpHeader, payloadData, payloadDataLength); case kRtpVp8Video: return ReceiveVp8Codec(rtpHeader, payloadData, payloadDataLength); @@ -386,13 +398,6 @@ WebRtc_Word32 RTPReceiverVideo::ReceiveGenericCodec( const WebRtc_UWord16 payloadDataLength) { rtpHeader->frameType = kVideoFrameKey; - bool isFirstPacketInFrame = - (_parent->SequenceNumber() + 1) == rtpHeader->header.sequenceNumber && - (_parent->TimeStamp() != rtpHeader->header.timestamp); - - if (isFirstPacketInFrame || _parent->HaveNotReceivedPackets()) { - rtpHeader->type.Video.isFirstPacket = true; - } _criticalSectionReceiverVideo->Leave(); if (data_callback_->OnReceivedPayloadData(payloadData, payloadDataLength, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h index 530c6b80f6..39dcbdae52 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h @@ -23,12 +23,12 @@ class CriticalSectionWrapper; class ModuleRtpRtcpImpl; class ReceiverFEC; class RTPReceiver; +class RTPPayloadRegistry; class RTPReceiverVideo : public RTPReceiverStrategy { public: - // TODO(phoglund): Get rid of dependency on "parent". RTPReceiverVideo(const WebRtc_Word32 id, - RTPReceiver* parent, + const RTPPayloadRegistry* rtp_payload_registry, RtpData* data_callback, ModuleRtpRtcpImpl* owner); @@ -40,7 +40,8 @@ class RTPReceiverVideo : public RTPReceiverStrategy { const bool is_red, const WebRtc_UWord8* packet, const WebRtc_UWord16 packet_length, - const WebRtc_Word64 timestamp); + const WebRtc_Word64 timestamp, + const bool is_first_packet); WebRtc_Word32 GetFrequencyHz() const; @@ -85,7 +86,8 @@ class RTPReceiverVideo : public RTPReceiverStrategy { WebRtcRTPHeader* rtpHeader, const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadDataLength, - const RtpVideoCodecTypes videoType); + const RtpVideoCodecTypes videoType, + const bool isFirstPacket); WebRtc_Word32 ReceiveGenericCodec(WebRtcRTPHeader *rtpHeader, const WebRtc_UWord8* payloadData, @@ -107,10 +109,11 @@ class RTPReceiverVideo : public RTPReceiverStrategy { const bool isRED, const WebRtc_UWord8* incomingRtpPacket, const WebRtc_UWord16 incomingRtpPacketSize, - const WebRtc_Word64 nowMS); + const WebRtc_Word64 nowMS, + const bool isFirstPacket); WebRtc_Word32 _id; - RTPReceiver* _parent; + const RTPPayloadRegistry* _rtpRtpPayloadRegistry; CriticalSectionWrapper* _criticalSectionReceiverVideo; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/source/rtp_rtcp.gypi index fe75625e87..030107954c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp.gypi +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp.gypi @@ -73,6 +73,8 @@ 'producer_fec.h', 'rtp_packet_history.cc', 'rtp_packet_history.h', + 'rtp_payload_registry.h', + 'rtp_payload_registry.cc', 'rtp_receiver_strategy.cc', 'rtp_receiver_strategy.h', 'rtp_receiver_video.cc',