266 lines
8.1 KiB
C++
266 lines
8.1 KiB
C++
|
|
/*
|
||
|
|
* 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
|