1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <assert.h>
12
13#include "webrtc/common_types.h"
14#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
15#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
16
17namespace webrtc {
18
19RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
20}
21
22RtpHeaderExtensionMap::~RtpHeaderExtensionMap() {
23  Erase();
24}
25
26void RtpHeaderExtensionMap::Erase() {
27  while (!extensionMap_.empty()) {
28    std::map<uint8_t, HeaderExtension*>::iterator it =
29        extensionMap_.begin();
30    delete it->second;
31    extensionMap_.erase(it);
32  }
33}
34
35int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
36                                        const uint8_t id) {
37  return Register(type, id, true);
38}
39
40int32_t RtpHeaderExtensionMap::RegisterInactive(const RTPExtensionType type,
41                                                const uint8_t id) {
42  return Register(type, id, false);
43}
44
45int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
46                                        const uint8_t id,
47                                        bool active) {
48  if (id < 1 || id > 14) {
49    return -1;
50  }
51  std::map<uint8_t, HeaderExtension*>::iterator it =
52      extensionMap_.find(id);
53  if (it != extensionMap_.end()) {
54    if (it->second->type != type) {
55      // An extension is already registered with the same id
56      // but a different type, so return failure.
57      return -1;
58    }
59    // This extension type is already registered with this id,
60    // so return success.
61    it->second->active = active;
62    return 0;
63  }
64  extensionMap_[id] = new HeaderExtension(type, active);
65  return 0;
66}
67
68bool RtpHeaderExtensionMap::SetActive(const RTPExtensionType type,
69                                      bool active) {
70  for (auto& kv : extensionMap_) {
71    if (kv.second->type == type) {
72      kv.second->active = active;
73      return true;
74    }
75  }
76  return false;
77}
78
79int32_t RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) {
80  uint8_t id;
81  if (GetId(type, &id) != 0) {
82    return 0;
83  }
84  std::map<uint8_t, HeaderExtension*>::iterator it =
85      extensionMap_.find(id);
86  assert(it != extensionMap_.end());
87  delete it->second;
88  extensionMap_.erase(it);
89  return 0;
90}
91
92bool RtpHeaderExtensionMap::IsRegistered(RTPExtensionType type) const {
93  std::map<uint8_t, HeaderExtension*>::const_iterator it =
94    extensionMap_.begin();
95  for (; it != extensionMap_.end(); ++it) {
96    if (it->second->type == type)
97      return true;
98  }
99  return false;
100}
101
102int32_t RtpHeaderExtensionMap::GetType(const uint8_t id,
103                                       RTPExtensionType* type) const {
104  assert(type);
105  std::map<uint8_t, HeaderExtension*>::const_iterator it =
106      extensionMap_.find(id);
107  if (it == extensionMap_.end()) {
108    return -1;
109  }
110  HeaderExtension* extension = it->second;
111  *type = extension->type;
112  return 0;
113}
114
115int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
116                                     uint8_t* id) const {
117  assert(id);
118  std::map<uint8_t, HeaderExtension*>::const_iterator it =
119      extensionMap_.begin();
120
121  while (it != extensionMap_.end()) {
122    HeaderExtension* extension = it->second;
123    if (extension->type == type) {
124      *id = it->first;
125      return 0;
126    }
127    it++;
128  }
129  return -1;
130}
131
132size_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
133  // Get length for each extension block.
134  size_t length = 0;
135  std::map<uint8_t, HeaderExtension*>::const_iterator it =
136      extensionMap_.begin();
137  while (it != extensionMap_.end()) {
138    HeaderExtension* extension = it->second;
139    if (extension->active) {
140      length += extension->length;
141    }
142    it++;
143  }
144  // Add RTP extension header length.
145  if (length > 0) {
146    length += kRtpOneByteHeaderLength;
147  }
148  // Pad up to nearest 32bit word.
149  length = RtpUtility::Word32Align(length);
150  return length;
151}
152
153int32_t RtpHeaderExtensionMap::GetLengthUntilBlockStartInBytes(
154    const RTPExtensionType type) const {
155  uint8_t id;
156  if (GetId(type, &id) != 0) {
157    // Not registered.
158    return -1;
159  }
160  // Get length until start of extension block type.
161  uint16_t length = kRtpOneByteHeaderLength;
162
163  std::map<uint8_t, HeaderExtension*>::const_iterator it =
164      extensionMap_.begin();
165  while (it != extensionMap_.end()) {
166    HeaderExtension* extension = it->second;
167    if (extension->type == type) {
168      if (!extension->active) {
169        return -1;
170      }
171      break;
172    } else if (extension->active) {
173      length += extension->length;
174    }
175    it++;
176  }
177  return length;
178}
179
180int32_t RtpHeaderExtensionMap::Size() const {
181  int32_t count = 0;
182  for (auto& kv : extensionMap_) {
183    if (kv.second->active) {
184      count++;
185    }
186  }
187  return count;
188}
189
190RTPExtensionType RtpHeaderExtensionMap::First() const {
191  for (auto& kv : extensionMap_) {
192    if (kv.second->active) {
193      return kv.second->type;
194    }
195  }
196
197  return kRtpExtensionNone;
198}
199
200RTPExtensionType RtpHeaderExtensionMap::Next(RTPExtensionType type) const {
201  uint8_t id;
202  if (GetId(type, &id) != 0) {
203    return kRtpExtensionNone;
204  }
205  std::map<uint8_t, HeaderExtension*>::const_iterator it =
206      extensionMap_.find(id);
207  if (it == extensionMap_.end() || !it->second->active) {
208    return kRtpExtensionNone;
209  }
210  while ((++it) != extensionMap_.end()) {
211    if (it->second->active) {
212      return it->second->type;
213    }
214  }
215
216  return kRtpExtensionNone;
217}
218
219void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
220  assert(map);
221  std::map<uint8_t, HeaderExtension*>::const_iterator it =
222      extensionMap_.begin();
223  while (it != extensionMap_.end()) {
224    HeaderExtension* extension = it->second;
225    map->Register(extension->type, it->first, extension->active);
226    it++;
227  }
228}
229}  // namespace webrtc
230