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
16namespace webrtc {
17
18RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
19}
20
21RtpHeaderExtensionMap::~RtpHeaderExtensionMap() {
22  Erase();
23}
24
25void RtpHeaderExtensionMap::Erase() {
26  while (!extensionMap_.empty()) {
27    std::map<uint8_t, HeaderExtension*>::iterator it =
28        extensionMap_.begin();
29    delete it->second;
30    extensionMap_.erase(it);
31  }
32}
33
34int32_t RtpHeaderExtensionMap::Register(const RTPExtensionType type,
35                                        const uint8_t id) {
36  if (id < 1 || id > 14) {
37    return -1;
38  }
39  std::map<uint8_t, HeaderExtension*>::iterator it =
40      extensionMap_.find(id);
41  if (it != extensionMap_.end()) {
42    if (it->second->type != type) {
43      // An extension is already registered with the same id
44      // but a different type, so return failure.
45      return -1;
46    }
47    // This extension type is already registered with this id,
48    // so return success.
49    return 0;
50  }
51  extensionMap_[id] = new HeaderExtension(type);
52  return 0;
53}
54
55int32_t RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) {
56  uint8_t id;
57  if (GetId(type, &id) != 0) {
58    return 0;
59  }
60  std::map<uint8_t, HeaderExtension*>::iterator it =
61      extensionMap_.find(id);
62  assert(it != extensionMap_.end());
63  delete it->second;
64  extensionMap_.erase(it);
65  return 0;
66}
67
68bool RtpHeaderExtensionMap::IsRegistered(RTPExtensionType type) const {
69  std::map<uint8_t, HeaderExtension*>::const_iterator it =
70    extensionMap_.begin();
71  for (; it != extensionMap_.end(); ++it) {
72    if (it->second->type == type)
73      return true;
74  }
75  return false;
76}
77
78int32_t RtpHeaderExtensionMap::GetType(const uint8_t id,
79                                       RTPExtensionType* type) const {
80  assert(type);
81  std::map<uint8_t, HeaderExtension*>::const_iterator it =
82      extensionMap_.find(id);
83  if (it == extensionMap_.end()) {
84    return -1;
85  }
86  HeaderExtension* extension = it->second;
87  *type = extension->type;
88  return 0;
89}
90
91int32_t RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
92                                     uint8_t* id) const {
93  assert(id);
94  std::map<uint8_t, HeaderExtension*>::const_iterator it =
95      extensionMap_.begin();
96
97  while (it != extensionMap_.end()) {
98    HeaderExtension* extension = it->second;
99    if (extension->type == type) {
100      *id = it->first;
101      return 0;
102    }
103    it++;
104  }
105  return -1;
106}
107
108uint16_t RtpHeaderExtensionMap::GetTotalLengthInBytes() const {
109  // Get length for each extension block.
110  uint16_t length = 0;
111  std::map<uint8_t, HeaderExtension*>::const_iterator it =
112      extensionMap_.begin();
113  while (it != extensionMap_.end()) {
114    HeaderExtension* extension = it->second;
115    length += extension->length;
116    it++;
117  }
118  // Add RTP extension header length.
119  if (length > 0) {
120    length += kRtpOneByteHeaderLength;
121  }
122  return length;
123}
124
125int32_t RtpHeaderExtensionMap::GetLengthUntilBlockStartInBytes(
126    const RTPExtensionType type) const {
127  uint8_t id;
128  if (GetId(type, &id) != 0) {
129    // Not registered.
130    return -1;
131  }
132  // Get length until start of extension block type.
133  uint16_t length = kRtpOneByteHeaderLength;
134
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->type == type) {
140      break;
141    } else {
142      length += extension->length;
143    }
144    it++;
145  }
146  return length;
147}
148
149int32_t RtpHeaderExtensionMap::Size() const {
150  return extensionMap_.size();
151}
152
153RTPExtensionType RtpHeaderExtensionMap::First() const {
154  std::map<uint8_t, HeaderExtension*>::const_iterator it =
155      extensionMap_.begin();
156  if (it == extensionMap_.end()) {
157     return kRtpExtensionNone;
158  }
159  HeaderExtension* extension = it->second;
160  return extension->type;
161}
162
163RTPExtensionType RtpHeaderExtensionMap::Next(RTPExtensionType type) const {
164  uint8_t id;
165  if (GetId(type, &id) != 0) {
166    return kRtpExtensionNone;
167  }
168  std::map<uint8_t, HeaderExtension*>::const_iterator it =
169      extensionMap_.find(id);
170  if (it == extensionMap_.end()) {
171    return kRtpExtensionNone;
172  }
173  it++;
174  if (it == extensionMap_.end()) {
175    return kRtpExtensionNone;
176  }
177  HeaderExtension* extension = it->second;
178  return extension->type;
179}
180
181void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
182  assert(map);
183  std::map<uint8_t, HeaderExtension*>::const_iterator it =
184      extensionMap_.begin();
185  while (it != extensionMap_.end()) {
186    HeaderExtension* extension = it->second;
187    map->Register(extension->type, it->first);
188    it++;
189  }
190}
191}  // namespace webrtc
192