Index: webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc |
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc |
index 7d4afc6e36199f77baa394779aa026be203bb9c1..a4354d393ea99cea9a6a0964a77c962fe8d6ab4b 100644 |
--- a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc |
+++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc |
@@ -10,76 +10,55 @@ |
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h" |
-#include <algorithm> |
- |
-#include "webrtc/base/checks.h" |
#include "webrtc/base/logging.h" |
-#include "webrtc/base/stringutils.h" |
#include "webrtc/common_types.h" |
#include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
namespace webrtc { |
-namespace { |
- |
-bool PayloadIsCompatible(const RtpUtility::Payload& payload, |
- const CodecInst& audio_codec) { |
- if (!payload.audio) |
- return false; |
- if (_stricmp(payload.name, audio_codec.plname) != 0) |
- return false; |
- const AudioPayload& audio_payload = payload.typeSpecific.Audio; |
- const uint32_t rate = std::max(0, audio_codec.rate); |
- return audio_payload.frequency == static_cast<uint32_t>(audio_codec.plfreq) && |
- audio_payload.channels == audio_codec.channels && |
- (audio_payload.rate == rate || audio_payload.rate == 0 || rate == 0); |
-} |
- |
-bool PayloadIsCompatible(const RtpUtility::Payload& payload, |
- const VideoCodec& video_codec) { |
- return !payload.audio && _stricmp(payload.name, video_codec.plName) == 0; |
-} |
- |
-RtpUtility::Payload CreatePayloadType(const CodecInst& audio_codec) { |
- RtpUtility::Payload payload; |
- payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; |
- strncpy(payload.name, audio_codec.plname, RTP_PAYLOAD_NAME_SIZE - 1); |
- RTC_DCHECK_GE(audio_codec.plfreq, 1000); |
- payload.typeSpecific.Audio.frequency = audio_codec.plfreq; |
- payload.typeSpecific.Audio.channels = audio_codec.channels; |
- payload.typeSpecific.Audio.rate = std::max(0, audio_codec.rate); |
- payload.audio = true; |
- return payload; |
-} |
- |
-RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) { |
- switch (type) { |
- case kVideoCodecVP8: |
- return kRtpVideoVp8; |
- case kVideoCodecVP9: |
- return kRtpVideoVp9; |
- case kVideoCodecH264: |
- return kRtpVideoH264; |
- case kVideoCodecRED: |
- case kVideoCodecULPFEC: |
- return kRtpVideoNone; |
- default: |
- return kRtpVideoGeneric; |
- } |
-} |
- |
-RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) { |
- RtpUtility::Payload payload; |
- payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; |
- strncpy(payload.name, video_codec.plName, RTP_PAYLOAD_NAME_SIZE - 1); |
- payload.typeSpecific.Video.videoCodecType = |
- ConvertToRtpVideoCodecType(video_codec.codecType); |
- payload.audio = false; |
- return payload; |
-} |
- |
-bool IsPayloadTypeValid(int8_t payload_type) { |
+RTPPayloadRegistry::RTPPayloadRegistry(RTPPayloadStrategy* rtp_payload_strategy) |
+ : rtp_payload_strategy_(rtp_payload_strategy), |
+ red_payload_type_(-1), |
+ ulpfec_payload_type_(-1), |
+ incoming_payload_type_(-1), |
+ last_received_payload_type_(-1), |
+ last_received_media_payload_type_(-1), |
+ rtx_(false), |
+ ssrc_rtx_(0) {} |
+ |
+RTPPayloadRegistry::~RTPPayloadRegistry() { |
+ while (!payload_type_map_.empty()) { |
+ RtpUtility::PayloadTypeMap::iterator it = payload_type_map_.begin(); |
+ delete it->second; |
+ payload_type_map_.erase(it); |
+ } |
+} |
+ |
+int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec, |
+ bool* created_new_payload) { |
+ return RegisterReceivePayload( |
+ audio_codec.plname, audio_codec.pltype, audio_codec.plfreq, |
+ audio_codec.channels, std::max(0, audio_codec.rate), created_new_payload); |
+} |
+ |
+int32_t RTPPayloadRegistry::RegisterReceivePayload( |
+ const VideoCodec& video_codec) { |
+ bool dummy_created_new_payload; |
+ return RegisterReceivePayload(video_codec.plName, video_codec.plType, |
+ kVideoPayloadTypeFrequency, 0 /* channels */, |
+ 0 /* rate */, &dummy_created_new_payload); |
+} |
+ |
+int32_t RTPPayloadRegistry::RegisterReceivePayload( |
+ const char* const payload_name, |
+ const int8_t payload_type, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate, |
+ bool* created_new_payload) { |
assert(payload_type >= 0); |
+ assert(payload_name); |
+ *created_new_payload = false; |
// Sanity check. |
switch (payload_type) { |
@@ -95,48 +74,58 @@ |
case 79: // 207 Extended report. |
LOG(LS_ERROR) << "Can't register invalid receiver payload type: " |
<< payload_type; |
- return false; |
+ return -1; |
default: |
- return true; |
- } |
-} |
- |
-} // namespace |
- |
-RTPPayloadRegistry::RTPPayloadRegistry() |
- : incoming_payload_type_(-1), |
- last_received_payload_type_(-1), |
- last_received_media_payload_type_(-1), |
- rtx_(false), |
- ssrc_rtx_(0) {} |
- |
-RTPPayloadRegistry::~RTPPayloadRegistry() = default; |
- |
-int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec, |
- bool* created_new_payload) { |
- *created_new_payload = false; |
- if (!IsPayloadTypeValid(audio_codec.pltype)) |
+ break; |
+ } |
+ |
+ size_t payload_name_length = strlen(payload_name); |
+ |
+ rtc::CritScope cs(&crit_sect_); |
+ |
+ RtpUtility::PayloadTypeMap::iterator it = |
+ payload_type_map_.find(payload_type); |
+ |
+ if (it != payload_type_map_.end()) { |
+ // We already use this payload type. |
+ RtpUtility::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 && |
+ RtpUtility::StringCompare( |
+ payload->name, payload_name, payload_name_length)) { |
+ if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, |
+ channels, rate)) { |
+ rtp_payload_strategy_->UpdatePayloadRate(payload, rate); |
+ return 0; |
+ } |
+ } |
+ LOG(LS_ERROR) << "Payload type already registered: " |
+ << static_cast<int>(payload_type); |
return -1; |
- |
- rtc::CritScope cs(&crit_sect_); |
- |
- auto it = payload_type_map_.find(audio_codec.pltype); |
- if (it != payload_type_map_.end()) { |
- // We already use this payload type. Check if it's the same as we already |
- // have. If same, ignore sending an error. |
- if (PayloadIsCompatible(it->second, audio_codec)) { |
- it->second.typeSpecific.Audio.rate = std::max(0, audio_codec.rate); |
- return 0; |
- } |
- LOG(LS_ERROR) << "Payload type already registered: " << audio_codec.pltype; |
- return -1; |
- } |
- |
- // Audio codecs must be unique. |
- DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_codec); |
- |
- payload_type_map_[audio_codec.pltype] = CreatePayloadType(audio_codec); |
+ } |
+ |
+ if (rtp_payload_strategy_->CodecsMustBeUnique()) { |
+ DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( |
+ payload_name, payload_name_length, frequency, channels, rate); |
+ } |
+ |
+ RtpUtility::Payload* payload = rtp_payload_strategy_->CreatePayloadType( |
+ payload_name, payload_type, frequency, channels, rate); |
+ |
+ payload_type_map_[payload_type] = payload; |
*created_new_payload = true; |
+ |
+ if (RtpUtility::StringCompare(payload_name, "red", 3)) { |
+ red_payload_type_ = payload_type; |
+ } else if (RtpUtility::StringCompare(payload_name, "ulpfec", 6)) { |
+ ulpfec_payload_type_ = payload_type; |
+ } |
// Successful set of payload type, clear the value of last received payload |
// type since it might mean something else. |
@@ -145,37 +134,14 @@ |
return 0; |
} |
-int32_t RTPPayloadRegistry::RegisterReceivePayload( |
- const VideoCodec& video_codec) { |
- if (!IsPayloadTypeValid(video_codec.plType)) |
- return -1; |
- |
- rtc::CritScope cs(&crit_sect_); |
- |
- auto it = payload_type_map_.find(video_codec.plType); |
- if (it != payload_type_map_.end()) { |
- // We already use this payload type. Check if it's the same as we already |
- // have. If same, ignore sending an error. |
- if (PayloadIsCompatible(it->second, video_codec)) |
- return 0; |
- LOG(LS_ERROR) << "Payload type already registered: " |
- << static_cast<int>(video_codec.plType); |
- return -1; |
- } |
- |
- payload_type_map_[video_codec.plType] = CreatePayloadType(video_codec); |
- |
- // 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; |
-} |
- |
int32_t RTPPayloadRegistry::DeRegisterReceivePayload( |
const int8_t payload_type) { |
rtc::CritScope cs(&crit_sect_); |
- payload_type_map_.erase(payload_type); |
+ RtpUtility::PayloadTypeMap::iterator it = |
+ payload_type_map_.find(payload_type); |
+ assert(it != payload_type_map_.end()); |
+ delete it->second; |
+ payload_type_map_.erase(it); |
return 0; |
} |
@@ -183,40 +149,95 @@ |
// for audio codecs, but there can for video. |
// Always called from within a critical section. |
void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType( |
- const CodecInst& audio_codec) { |
- for (auto iterator = payload_type_map_.begin(); |
- iterator != payload_type_map_.end(); ++iterator) { |
- if (PayloadIsCompatible(iterator->second, audio_codec)) { |
- // Remove old setting. |
- payload_type_map_.erase(iterator); |
- break; |
+ const char* const payload_name, |
+ const size_t payload_name_length, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate) { |
+ RtpUtility::PayloadTypeMap::iterator iterator = payload_type_map_.begin(); |
+ for (; iterator != payload_type_map_.end(); ++iterator) { |
+ RtpUtility::Payload* payload = iterator->second; |
+ size_t name_length = strlen(payload->name); |
+ |
+ if (payload_name_length == name_length && |
+ RtpUtility::StringCompare( |
+ payload->name, payload_name, payload_name_length)) { |
+ // We found the payload name in the list. |
+ // If audio, check frequency and rate. |
+ if (payload->audio) { |
+ if (rtp_payload_strategy_->PayloadIsCompatible(*payload, frequency, |
+ channels, rate)) { |
+ // Remove old setting. |
+ delete payload; |
+ payload_type_map_.erase(iterator); |
+ break; |
+ } |
+ } else if (RtpUtility::StringCompare(payload_name, "red", 3)) { |
+ delete payload; |
+ payload_type_map_.erase(iterator); |
+ break; |
+ } |
} |
} |
} |
int32_t RTPPayloadRegistry::ReceivePayloadType(const CodecInst& audio_codec, |
int8_t* payload_type) const { |
- assert(payload_type); |
- rtc::CritScope cs(&crit_sect_); |
- |
- for (const auto& it : payload_type_map_) { |
- if (PayloadIsCompatible(it.second, audio_codec)) { |
- *payload_type = it.first; |
- return 0; |
- } |
- } |
- return -1; |
+ return ReceivePayloadType(audio_codec.plname, audio_codec.plfreq, |
+ audio_codec.channels, std::max(0, audio_codec.rate), |
+ payload_type); |
} |
int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec, |
int8_t* payload_type) const { |
+ return ReceivePayloadType(video_codec.plName, kVideoPayloadTypeFrequency, |
+ 0 /* channels */, 0 /* rate */, payload_type); |
+} |
+ |
+int32_t RTPPayloadRegistry::ReceivePayloadType(const char* const payload_name, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate, |
+ int8_t* payload_type) const { |
assert(payload_type); |
- rtc::CritScope cs(&crit_sect_); |
- |
- for (const auto& it : payload_type_map_) { |
- if (PayloadIsCompatible(it.second, video_codec)) { |
- *payload_type = it.first; |
- return 0; |
+ size_t payload_name_length = strlen(payload_name); |
+ |
+ rtc::CritScope cs(&crit_sect_); |
+ |
+ RtpUtility::PayloadTypeMap::const_iterator it = payload_type_map_.begin(); |
+ |
+ for (; it != payload_type_map_.end(); ++it) { |
+ RtpUtility::Payload* payload = it->second; |
+ assert(payload); |
+ |
+ size_t name_length = strlen(payload->name); |
+ if (payload_name_length == name_length && |
+ RtpUtility::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; |
+ } |
} |
} |
return -1; |
@@ -312,8 +333,7 @@ |
bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const { |
rtc::CritScope cs(&crit_sect_); |
- auto it = payload_type_map_.find(header.payloadType); |
- return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0; |
+ return red_payload_type_ == header.payloadType; |
} |
bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const { |
@@ -323,13 +343,14 @@ |
bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type, |
PayloadUnion* payload) const { |
rtc::CritScope cs(&crit_sect_); |
- auto it = payload_type_map_.find(payload_type); |
+ RtpUtility::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 false; |
} |
- *payload = it->second.typeSpecific; |
+ *payload = it->second->typeSpecific; |
return true; |
} |
@@ -340,22 +361,22 @@ |
return -1; |
} |
rtc::CritScope cs(&crit_sect_); |
- return payload->audio ? payload->typeSpecific.Audio.frequency |
- : kVideoPayloadTypeFrequency; |
+ return rtp_payload_strategy_->GetPayloadTypeFrequency(*payload); |
} |
const RtpUtility::Payload* RTPPayloadRegistry::PayloadTypeToPayload( |
uint8_t payload_type) const { |
rtc::CritScope cs(&crit_sect_); |
- auto it = payload_type_map_.find(payload_type); |
+ RtpUtility::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 nullptr; |
} |
- return &it->second; |
+ return it->second; |
} |
void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) { |
@@ -374,15 +395,106 @@ |
return false; |
} |
-// Returns -1 if a payload with name |payload_name| is not registered. |
-int8_t RTPPayloadRegistry::GetPayloadTypeWithName( |
- const char* payload_name) const { |
- rtc::CritScope cs(&crit_sect_); |
- for (const auto& it : payload_type_map_) { |
- if (_stricmp(it.second.name, payload_name) == 0) |
- return it.first; |
- } |
- return -1; |
+class RTPPayloadAudioStrategy : public RTPPayloadStrategy { |
+ public: |
+ bool CodecsMustBeUnique() const override { return true; } |
+ |
+ bool PayloadIsCompatible(const RtpUtility::Payload& payload, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate) const override { |
+ return |
+ payload.audio && |
+ payload.typeSpecific.Audio.frequency == frequency && |
+ payload.typeSpecific.Audio.channels == channels && |
+ (payload.typeSpecific.Audio.rate == rate || |
+ payload.typeSpecific.Audio.rate == 0 || rate == 0); |
+ } |
+ |
+ void UpdatePayloadRate(RtpUtility::Payload* payload, |
+ const uint32_t rate) const override { |
+ payload->typeSpecific.Audio.rate = rate; |
+ } |
+ |
+ RtpUtility::Payload* CreatePayloadType(const char* const payloadName, |
+ const int8_t payloadType, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate) const override { |
+ RtpUtility::Payload* payload = new RtpUtility::Payload; |
+ payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; |
+ strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); |
+ assert(frequency >= 1000); |
+ payload->typeSpecific.Audio.frequency = frequency; |
+ payload->typeSpecific.Audio.channels = channels; |
+ payload->typeSpecific.Audio.rate = rate; |
+ payload->audio = true; |
+ return payload; |
+ } |
+ |
+ int GetPayloadTypeFrequency( |
+ const RtpUtility::Payload& payload) const override { |
+ return payload.typeSpecific.Audio.frequency; |
+ } |
+}; |
+ |
+class RTPPayloadVideoStrategy : public RTPPayloadStrategy { |
+ public: |
+ bool CodecsMustBeUnique() const override { return false; } |
+ |
+ bool PayloadIsCompatible(const RtpUtility::Payload& payload, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate) const override { |
+ return !payload.audio; |
+ } |
+ |
+ void UpdatePayloadRate(RtpUtility::Payload* payload, |
+ const uint32_t rate) const override {} |
+ |
+ RtpUtility::Payload* CreatePayloadType(const char* const payloadName, |
+ const int8_t payloadType, |
+ const uint32_t frequency, |
+ const size_t channels, |
+ const uint32_t rate) const override { |
+ RtpVideoCodecTypes videoType = kRtpVideoGeneric; |
+ |
+ if (RtpUtility::StringCompare(payloadName, "VP8", 3)) { |
+ videoType = kRtpVideoVp8; |
+ } else if (RtpUtility::StringCompare(payloadName, "VP9", 3)) { |
+ videoType = kRtpVideoVp9; |
+ } else if (RtpUtility::StringCompare(payloadName, "H264", 4)) { |
+ videoType = kRtpVideoH264; |
+ } else if (RtpUtility::StringCompare(payloadName, "I420", 4)) { |
+ videoType = kRtpVideoGeneric; |
+ } else if (RtpUtility::StringCompare(payloadName, "ULPFEC", 6) || |
+ RtpUtility::StringCompare(payloadName, "RED", 3)) { |
+ videoType = kRtpVideoNone; |
+ } else { |
+ videoType = kRtpVideoGeneric; |
+ } |
+ RtpUtility::Payload* payload = new RtpUtility::Payload; |
+ |
+ payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0; |
+ strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1); |
+ payload->typeSpecific.Video.videoCodecType = videoType; |
+ payload->audio = false; |
+ return payload; |
+ } |
+ |
+ int GetPayloadTypeFrequency( |
+ const RtpUtility::Payload& payload) const override { |
+ return kVideoPayloadTypeFrequency; |
+ } |
+}; |
+ |
+RTPPayloadStrategy* RTPPayloadStrategy::CreateStrategy( |
+ const bool handling_audio) { |
+ if (handling_audio) { |
+ return new RTPPayloadAudioStrategy(); |
+ } else { |
+ return new RTPPayloadVideoStrategy(); |
+ } |
} |
} // namespace webrtc |