OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
| 11 #include <assert.h> |
| 12 |
| 13 #include "webrtc/base/checks.h" |
| 14 #include "webrtc/common_types.h" |
11 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" | 15 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" |
12 | |
13 #include "webrtc/base/arraysize.h" | |
14 #include "webrtc/base/checks.h" | |
15 #include "webrtc/base/logging.h" | |
16 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" | |
17 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 16 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
18 | 17 |
19 namespace webrtc { | 18 namespace webrtc { |
20 namespace { | |
21 | 19 |
22 using RtpUtility::Word32Align; | 20 constexpr uint8_t RtpHeaderExtensionMap::kInvalidId; |
23 | 21 |
24 struct ExtensionInfo { | 22 RtpHeaderExtensionMap::RtpHeaderExtensionMap() { |
25 RTPExtensionType type; | |
26 size_t value_size; | |
27 const char* uri; | |
28 }; | |
29 | |
30 template <typename Extension> | |
31 constexpr ExtensionInfo CreateExtensionInfo() { | |
32 return {Extension::kId, Extension::kValueSizeBytes, Extension::kUri}; | |
33 } | 23 } |
34 | 24 |
35 constexpr ExtensionInfo kExtensions[] = { | 25 RtpHeaderExtensionMap::~RtpHeaderExtensionMap() { |
36 CreateExtensionInfo<TransmissionOffset>(), | 26 Erase(); |
37 CreateExtensionInfo<AudioLevel>(), | 27 } |
38 CreateExtensionInfo<AbsoluteSendTime>(), | |
39 CreateExtensionInfo<VideoOrientation>(), | |
40 CreateExtensionInfo<TransportSequenceNumber>(), | |
41 CreateExtensionInfo<PlayoutDelayLimits>(), | |
42 }; | |
43 | 28 |
44 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual | 29 void RtpHeaderExtensionMap::Erase() { |
45 // number of known extensions. | 30 while (!extensionMap_.empty()) { |
46 static_assert(arraysize(kExtensions) == | 31 std::map<uint8_t, HeaderExtension*>::iterator it = |
47 static_cast<int>(kRtpExtensionNumberOfExtensions) - 1, | 32 extensionMap_.begin(); |
48 "kExtensions expect to list all known extensions"); | 33 delete it->second; |
| 34 extensionMap_.erase(it); |
| 35 } |
| 36 } |
49 | 37 |
50 size_t ValueSize(RTPExtensionType type) { | 38 int32_t RtpHeaderExtensionMap::Register(RTPExtensionType type, uint8_t id) { |
51 for (const ExtensionInfo& extension : kExtensions) | 39 if (id < 1 || id > 14) { |
52 if (type == extension.type) | 40 return -1; |
53 return extension.value_size; | 41 } |
54 | 42 std::map<uint8_t, HeaderExtension*>::iterator it = |
55 RTC_NOTREACHED(); | 43 extensionMap_.find(id); |
| 44 if (it != extensionMap_.end()) { |
| 45 if (it->second->type != type) { |
| 46 // An extension is already registered with the same id |
| 47 // but a different type, so return failure. |
| 48 return -1; |
| 49 } |
| 50 // This extension type is already registered with this id, |
| 51 // so return success. |
| 52 return 0; |
| 53 } |
| 54 RTC_DCHECK_EQ(kInvalidId, GetId(type)); |
| 55 extensionMap_[id] = new HeaderExtension(type); |
56 return 0; | 56 return 0; |
57 } | 57 } |
58 | 58 |
59 } // namespace | 59 int32_t RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) { |
60 | 60 uint8_t id; |
61 constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType; | 61 if (GetId(type, &id) != 0) { |
62 constexpr uint8_t RtpHeaderExtensionMap::kInvalidId; | 62 return 0; |
63 constexpr uint8_t RtpHeaderExtensionMap::kMinId; | 63 } |
64 constexpr uint8_t RtpHeaderExtensionMap::kMaxId; | 64 std::map<uint8_t, HeaderExtension*>::iterator it = |
65 | 65 extensionMap_.find(id); |
66 RtpHeaderExtensionMap::RtpHeaderExtensionMap() { | 66 assert(it != extensionMap_.end()); |
67 total_values_size_bytes_ = 0; | 67 delete it->second; |
68 for (auto& type : types_) | 68 extensionMap_.erase(it); |
69 type = kInvalidType; | 69 return 0; |
70 for (auto& id : ids_) | |
71 id = kInvalidId; | |
72 } | 70 } |
73 | 71 |
74 RtpHeaderExtensionMap::RtpHeaderExtensionMap( | 72 bool RtpHeaderExtensionMap::IsRegistered(RTPExtensionType type) const { |
75 std::initializer_list<RtpExtension> extensions) | 73 std::map<uint8_t, HeaderExtension*>::const_iterator it = |
76 : RtpHeaderExtensionMap() { | 74 extensionMap_.begin(); |
77 for (const RtpExtension& extension : extensions) | 75 for (; it != extensionMap_.end(); ++it) { |
78 RegisterByUri(extension.id, extension.uri); | 76 if (it->second->type == type) |
79 } | 77 return true; |
80 | 78 } |
81 bool RtpHeaderExtensionMap::RegisterByType(uint8_t id, RTPExtensionType type) { | |
82 for (const ExtensionInfo& extension : kExtensions) | |
83 if (type == extension.type) | |
84 return Register(id, extension.type, extension.value_size, extension.uri); | |
85 RTC_NOTREACHED(); | |
86 return false; | 79 return false; |
87 } | 80 } |
88 | 81 |
89 bool RtpHeaderExtensionMap::RegisterByUri(uint8_t id, const std::string& uri) { | 82 int32_t RtpHeaderExtensionMap::GetType(const uint8_t id, |
90 for (const ExtensionInfo& extension : kExtensions) | 83 RTPExtensionType* type) const { |
91 if (uri == extension.uri) | 84 assert(type); |
92 return Register(id, extension.type, extension.value_size, extension.uri); | 85 std::map<uint8_t, HeaderExtension*>::const_iterator it = |
93 LOG(LS_WARNING) << "Unknown extension uri:'" << uri | 86 extensionMap_.find(id); |
94 << "', id: " << static_cast<int>(id) << '.'; | 87 if (it == extensionMap_.end()) { |
95 return false; | 88 return -1; |
| 89 } |
| 90 HeaderExtension* extension = it->second; |
| 91 *type = extension->type; |
| 92 return 0; |
| 93 } |
| 94 |
| 95 RTPExtensionType RtpHeaderExtensionMap::GetType(uint8_t id) const { |
| 96 auto it = extensionMap_.find(id); |
| 97 if (it == extensionMap_.end()) { |
| 98 return kInvalidType; |
| 99 } |
| 100 return it->second->type; |
| 101 } |
| 102 |
| 103 int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type, |
| 104 uint8_t* id) const { |
| 105 assert(id); |
| 106 std::map<uint8_t, HeaderExtension*>::const_iterator it = |
| 107 extensionMap_.begin(); |
| 108 |
| 109 while (it != extensionMap_.end()) { |
| 110 HeaderExtension* extension = it->second; |
| 111 if (extension->type == type) { |
| 112 *id = it->first; |
| 113 return 0; |
| 114 } |
| 115 it++; |
| 116 } |
| 117 return -1; |
| 118 } |
| 119 |
| 120 uint8_t RtpHeaderExtensionMap::GetId(RTPExtensionType type) const { |
| 121 for (auto kv : extensionMap_) { |
| 122 if (kv.second->type == type) |
| 123 return kv.first; |
| 124 } |
| 125 return kInvalidId; |
96 } | 126 } |
97 | 127 |
98 size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const { | 128 size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const { |
99 if (total_values_size_bytes_ == 0) | 129 // Get length for each extension block. |
100 return 0; | 130 size_t length = 0; |
101 return Word32Align(kRtpOneByteHeaderLength + total_values_size_bytes_); | 131 for (const auto& kv : extensionMap_) |
| 132 length += kv.second->length; |
| 133 // Add RTP extension header length. |
| 134 if (length > 0) |
| 135 length += kRtpOneByteHeaderLength; |
| 136 // Pad up to nearest 32bit word. |
| 137 length = RtpUtility::Word32Align(length); |
| 138 return length; |
102 } | 139 } |
103 | 140 |
104 int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) { | 141 int32_t RtpHeaderExtensionMap::Size() const { |
105 if (IsRegistered(type)) { | 142 return extensionMap_.size(); |
106 uint8_t id = GetId(type); | |
107 total_values_size_bytes_ -= (ValueSize(type) + 1); | |
108 types_[id] = kInvalidType; | |
109 ids_[type] = kInvalidId; | |
110 } | |
111 return 0; | |
112 } | 143 } |
113 | 144 |
114 bool RtpHeaderExtensionMap::Register(uint8_t id, | 145 void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const { |
115 RTPExtensionType type, | 146 assert(map); |
116 size_t value_size, | 147 std::map<uint8_t, HeaderExtension*>::const_iterator it = |
117 const char* uri) { | 148 extensionMap_.begin(); |
118 RTC_DCHECK_GT(type, kRtpExtensionNone); | 149 while (it != extensionMap_.end()) { |
119 RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions); | 150 HeaderExtension* extension = it->second; |
120 RTC_DCHECK_GE(value_size, 1U); | 151 map->Register(extension->type, it->first); |
121 RTC_DCHECK_LE(value_size, 16U); | 152 it++; |
122 | |
123 if (id < kMinId || id > kMaxId) { | |
124 LOG(LS_WARNING) << "Failed to register extension uri:'" << uri | |
125 << "' with invalid id:" << static_cast<int>(id) << "."; | |
126 return false; | |
127 } | 153 } |
128 | |
129 if (GetType(id) == type) { // Same type/id pair already registered. | |
130 LOG(LS_VERBOSE) << "Reregistering extension uri:'" << uri | |
131 << "', id:" << static_cast<int>(id); | |
132 return true; | |
133 } | |
134 | |
135 if (GetType(id) != kInvalidType) { // |id| used by another extension type. | |
136 LOG(LS_WARNING) << "Failed to register extension uri:'" << uri | |
137 << "', id:" << static_cast<int>(id) | |
138 << ". Id already in use by extension type " | |
139 << static_cast<int>(GetType(id)); | |
140 return false; | |
141 } | |
142 RTC_DCHECK(!IsRegistered(type)); | |
143 | |
144 types_[id] = type; | |
145 ids_[type] = id; | |
146 total_values_size_bytes_ += (value_size + 1); | |
147 return true; | |
148 } | 154 } |
149 | |
150 } // namespace webrtc | 155 } // namespace webrtc |
OLD | NEW |