| /* |
| * 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 |