Moving src/webrtc into src/.
In order to eliminate the WebRTC Subtree mirror in Chromium, WebRTC is moving the content of the src/webrtc directory up to the src/ directory. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38 Reviewed-on: https://webrtc-review.googlesource.com/1560 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19845}
This commit is contained in:
committed by
Commit Bot
parent
6674846b4a
commit
bb547203bf
371
modules/rtp_rtcp/source/rtp_payload_registry.cc
Normal file
371
modules/rtp_rtcp/source/rtp_payload_registry.cc
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/include/rtp_payload_registry.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h"
|
||||
#include "webrtc/rtc_base/checks.h"
|
||||
#include "webrtc/rtc_base/logging.h"
|
||||
#include "webrtc/rtc_base/stringutils.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;
|
||||
return audio_payload.frequency == static_cast<uint32_t>(audio_codec.plfreq) &&
|
||||
audio_payload.channels == audio_codec.channels;
|
||||
}
|
||||
|
||||
bool PayloadIsCompatible(const RtpUtility::Payload& payload,
|
||||
const VideoCodec& video_codec) {
|
||||
if (payload.audio || _stricmp(payload.name, video_codec.plName) != 0)
|
||||
return false;
|
||||
// For H264, profiles must match as well.
|
||||
if (video_codec.codecType == kVideoCodecH264) {
|
||||
return video_codec.H264().profile ==
|
||||
payload.typeSpecific.Video.h264_profile;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
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);
|
||||
if (video_codec.codecType == kVideoCodecH264)
|
||||
payload.typeSpecific.Video.h264_profile = video_codec.H264().profile;
|
||||
payload.audio = false;
|
||||
return payload;
|
||||
}
|
||||
|
||||
bool IsPayloadTypeValid(int8_t payload_type) {
|
||||
assert(payload_type >= 0);
|
||||
|
||||
// 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.
|
||||
LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
|
||||
<< payload_type;
|
||||
return false;
|
||||
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;
|
||||
|
||||
void RTPPayloadRegistry::SetAudioReceivePayloads(
|
||||
std::map<int, SdpAudioFormat> codecs) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
RTC_DCHECK(!used_for_video_);
|
||||
used_for_audio_ = true;
|
||||
#endif
|
||||
|
||||
payload_type_map_.clear();
|
||||
for (const auto& kv : codecs) {
|
||||
const int& rtp_payload_type = kv.first;
|
||||
const SdpAudioFormat& audio_format = kv.second;
|
||||
const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format);
|
||||
RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
|
||||
payload_type_map_.insert(
|
||||
std::make_pair(rtp_payload_type, CreatePayloadType(ci)));
|
||||
}
|
||||
|
||||
// Clear the value of last received payload type since it might mean
|
||||
// something else now.
|
||||
last_received_payload_type_ = -1;
|
||||
last_received_media_payload_type_ = -1;
|
||||
}
|
||||
|
||||
int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
|
||||
bool* created_new_payload) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
RTC_DCHECK(!used_for_video_);
|
||||
used_for_audio_ = true;
|
||||
#endif
|
||||
|
||||
*created_new_payload = false;
|
||||
if (!IsPayloadTypeValid(audio_codec.pltype))
|
||||
return -1;
|
||||
|
||||
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 = 0;
|
||||
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);
|
||||
*created_new_payload = true;
|
||||
|
||||
// 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::RegisterReceivePayload(
|
||||
const VideoCodec& video_codec) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
|
||||
#if RTC_DCHECK_IS_ON
|
||||
RTC_DCHECK(!used_for_audio_);
|
||||
used_for_video_ = true;
|
||||
#endif
|
||||
|
||||
if (!IsPayloadTypeValid(video_codec.plType))
|
||||
return -1;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// There can't be several codecs with the same rate, frequency and channels
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_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, video_codec)) {
|
||||
*payload_type = it.first;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool RTPPayloadRegistry::RtxEnabled() const {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
return rtx_;
|
||||
}
|
||||
|
||||
bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
|
||||
return rtx_ && ssrc_rtx_ == header.ssrc;
|
||||
}
|
||||
|
||||
void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
ssrc_rtx_ = ssrc;
|
||||
rtx_ = true;
|
||||
}
|
||||
|
||||
bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
*ssrc = ssrc_rtx_;
|
||||
return rtx_;
|
||||
}
|
||||
|
||||
void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
|
||||
int associated_payload_type) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
if (payload_type < 0) {
|
||||
LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
|
||||
return;
|
||||
}
|
||||
|
||||
rtx_payload_type_map_[payload_type] = associated_payload_type;
|
||||
rtx_ = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
|
||||
PayloadUnion* payload) const {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
auto 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;
|
||||
return true;
|
||||
}
|
||||
|
||||
int RTPPayloadRegistry::GetPayloadTypeFrequency(
|
||||
uint8_t payload_type) const {
|
||||
const RtpUtility::Payload* payload = PayloadTypeToPayload(payload_type);
|
||||
if (!payload) {
|
||||
return -1;
|
||||
}
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
return payload->audio ? payload->typeSpecific.Audio.frequency
|
||||
: kVideoPayloadTypeFrequency;
|
||||
}
|
||||
|
||||
const RtpUtility::Payload* RTPPayloadRegistry::PayloadTypeToPayload(
|
||||
uint8_t payload_type) const {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
|
||||
auto 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;
|
||||
}
|
||||
|
||||
void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
if (!IsRtxInternal(header))
|
||||
incoming_payload_type_ = header.payloadType;
|
||||
}
|
||||
|
||||
bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
|
||||
rtc::CritScope cs(&crit_sect_);
|
||||
if (last_received_media_payload_type_ == media_payload_type) {
|
||||
// Media type unchanged.
|
||||
return true;
|
||||
}
|
||||
last_received_media_payload_type_ = media_payload_type;
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Reference in New Issue
Block a user