OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2004 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include "talk/media/base/codec.h" | |
29 | |
30 #include <algorithm> | |
31 #include <sstream> | |
32 | |
33 #include "webrtc/base/common.h" | |
34 #include "webrtc/base/logging.h" | |
35 #include "webrtc/base/stringencode.h" | |
36 #include "webrtc/base/stringutils.h" | |
37 | |
38 namespace cricket { | |
39 | |
40 const int kMaxPayloadId = 127; | |
41 | |
42 bool FeedbackParam::operator==(const FeedbackParam& other) const { | |
43 return _stricmp(other.id().c_str(), id().c_str()) == 0 && | |
44 _stricmp(other.param().c_str(), param().c_str()) == 0; | |
45 } | |
46 | |
47 bool FeedbackParams::operator==(const FeedbackParams& other) const { | |
48 return params_ == other.params_; | |
49 } | |
50 | |
51 bool FeedbackParams::Has(const FeedbackParam& param) const { | |
52 return std::find(params_.begin(), params_.end(), param) != params_.end(); | |
53 } | |
54 | |
55 void FeedbackParams::Add(const FeedbackParam& param) { | |
56 if (param.id().empty()) { | |
57 return; | |
58 } | |
59 if (Has(param)) { | |
60 // Param already in |this|. | |
61 return; | |
62 } | |
63 params_.push_back(param); | |
64 ASSERT(!HasDuplicateEntries()); | |
65 } | |
66 | |
67 void FeedbackParams::Intersect(const FeedbackParams& from) { | |
68 std::vector<FeedbackParam>::iterator iter_to = params_.begin(); | |
69 while (iter_to != params_.end()) { | |
70 if (!from.Has(*iter_to)) { | |
71 iter_to = params_.erase(iter_to); | |
72 } else { | |
73 ++iter_to; | |
74 } | |
75 } | |
76 } | |
77 | |
78 bool FeedbackParams::HasDuplicateEntries() const { | |
79 for (std::vector<FeedbackParam>::const_iterator iter = params_.begin(); | |
80 iter != params_.end(); ++iter) { | |
81 for (std::vector<FeedbackParam>::const_iterator found = iter + 1; | |
82 found != params_.end(); ++found) { | |
83 if (*found == *iter) { | |
84 return true; | |
85 } | |
86 } | |
87 } | |
88 return false; | |
89 } | |
90 | |
91 Codec::Codec(int id, const std::string& name, int clockrate, int preference) | |
92 : id(id), name(name), clockrate(clockrate), preference(preference) { | |
93 } | |
94 | |
95 Codec::Codec() : id(0), clockrate(0), preference(0) { | |
96 } | |
97 | |
98 Codec::Codec(const Codec& c) = default; | |
99 | |
100 Codec::~Codec() = default; | |
101 | |
102 Codec& Codec::operator=(const Codec& c) { | |
103 this->id = c.id; // id is reserved in objective-c | |
104 name = c.name; | |
105 clockrate = c.clockrate; | |
106 preference = c.preference; | |
107 params = c.params; | |
108 feedback_params = c.feedback_params; | |
109 return *this; | |
110 } | |
111 | |
112 bool Codec::operator==(const Codec& c) const { | |
113 return this->id == c.id && // id is reserved in objective-c | |
114 name == c.name && clockrate == c.clockrate && | |
115 preference == c.preference && params == c.params && | |
116 feedback_params == c.feedback_params; | |
117 } | |
118 | |
119 bool Codec::Matches(const Codec& codec) const { | |
120 // Match the codec id/name based on the typical static/dynamic name rules. | |
121 // Matching is case-insensitive. | |
122 const int kMaxStaticPayloadId = 95; | |
123 return (codec.id <= kMaxStaticPayloadId) ? | |
124 (id == codec.id) : (_stricmp(name.c_str(), codec.name.c_str()) == 0); | |
125 } | |
126 | |
127 bool Codec::GetParam(const std::string& name, std::string* out) const { | |
128 CodecParameterMap::const_iterator iter = params.find(name); | |
129 if (iter == params.end()) | |
130 return false; | |
131 *out = iter->second; | |
132 return true; | |
133 } | |
134 | |
135 bool Codec::GetParam(const std::string& name, int* out) const { | |
136 CodecParameterMap::const_iterator iter = params.find(name); | |
137 if (iter == params.end()) | |
138 return false; | |
139 return rtc::FromString(iter->second, out); | |
140 } | |
141 | |
142 void Codec::SetParam(const std::string& name, const std::string& value) { | |
143 params[name] = value; | |
144 } | |
145 | |
146 void Codec::SetParam(const std::string& name, int value) { | |
147 params[name] = rtc::ToString(value); | |
148 } | |
149 | |
150 bool Codec::RemoveParam(const std::string& name) { | |
151 return params.erase(name) == 1; | |
152 } | |
153 | |
154 void Codec::AddFeedbackParam(const FeedbackParam& param) { | |
155 feedback_params.Add(param); | |
156 } | |
157 | |
158 bool Codec::HasFeedbackParam(const FeedbackParam& param) const { | |
159 return feedback_params.Has(param); | |
160 } | |
161 | |
162 void Codec::IntersectFeedbackParams(const Codec& other) { | |
163 feedback_params.Intersect(other.feedback_params); | |
164 } | |
165 | |
166 AudioCodec::AudioCodec(int id, | |
167 const std::string& name, | |
168 int clockrate, | |
169 int bitrate, | |
170 size_t channels, | |
171 int preference) | |
172 : Codec(id, name, clockrate, preference), | |
173 bitrate(bitrate), | |
174 channels(channels) { | |
175 } | |
176 | |
177 AudioCodec::AudioCodec() : Codec(), bitrate(0), channels(0) { | |
178 } | |
179 | |
180 AudioCodec::AudioCodec(const AudioCodec& c) = default; | |
181 | |
182 AudioCodec& AudioCodec::operator=(const AudioCodec& c) { | |
183 Codec::operator=(c); | |
184 bitrate = c.bitrate; | |
185 channels = c.channels; | |
186 return *this; | |
187 } | |
188 | |
189 bool AudioCodec::operator==(const AudioCodec& c) const { | |
190 return bitrate == c.bitrate && channels == c.channels && Codec::operator==(c); | |
191 } | |
192 | |
193 bool AudioCodec::Matches(const AudioCodec& codec) const { | |
194 // If a nonzero clockrate is specified, it must match the actual clockrate. | |
195 // If a nonzero bitrate is specified, it must match the actual bitrate, | |
196 // unless the codec is VBR (0), where we just force the supplied value. | |
197 // The number of channels must match exactly, with the exception | |
198 // that channels=0 is treated synonymously as channels=1, per RFC | |
199 // 4566 section 6: " [The channels] parameter is OPTIONAL and may be | |
200 // omitted if the number of channels is one." | |
201 // Preference is ignored. | |
202 // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default clockrate. | |
203 return Codec::Matches(codec) && | |
204 ((codec.clockrate == 0 /*&& clockrate == 8000*/) || | |
205 clockrate == codec.clockrate) && | |
206 (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) && | |
207 ((codec.channels < 2 && channels < 2) || channels == codec.channels); | |
208 } | |
209 | |
210 std::string AudioCodec::ToString() const { | |
211 std::ostringstream os; | |
212 os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate | |
213 << ":" << channels << ":" << preference << "]"; | |
214 return os.str(); | |
215 } | |
216 | |
217 std::string VideoCodec::ToString() const { | |
218 std::ostringstream os; | |
219 os << "VideoCodec[" << id << ":" << name << ":" << width << ":" << height | |
220 << ":" << framerate << ":" << preference << "]"; | |
221 return os.str(); | |
222 } | |
223 | |
224 VideoCodec::VideoCodec(int id, | |
225 const std::string& name, | |
226 int width, | |
227 int height, | |
228 int framerate, | |
229 int preference) | |
230 : Codec(id, name, kVideoCodecClockrate, preference), | |
231 width(width), | |
232 height(height), | |
233 framerate(framerate) { | |
234 } | |
235 | |
236 VideoCodec::VideoCodec(int id, const std::string& name) | |
237 : Codec(id, name, kVideoCodecClockrate, 0), | |
238 width(0), | |
239 height(0), | |
240 framerate(0) { | |
241 } | |
242 | |
243 VideoCodec::VideoCodec() : Codec(), width(0), height(0), framerate(0) { | |
244 clockrate = kVideoCodecClockrate; | |
245 } | |
246 | |
247 VideoCodec::VideoCodec(const VideoCodec& c) = default; | |
248 | |
249 VideoCodec& VideoCodec::operator=(const VideoCodec& c) { | |
250 Codec::operator=(c); | |
251 width = c.width; | |
252 height = c.height; | |
253 framerate = c.framerate; | |
254 return *this; | |
255 } | |
256 | |
257 bool VideoCodec::operator==(const VideoCodec& c) const { | |
258 return width == c.width && height == c.height && framerate == c.framerate && | |
259 Codec::operator==(c); | |
260 } | |
261 | |
262 VideoCodec VideoCodec::CreateRtxCodec(int rtx_payload_type, | |
263 int associated_payload_type) { | |
264 VideoCodec rtx_codec(rtx_payload_type, kRtxCodecName, 0, 0, 0, 0); | |
265 rtx_codec.SetParam(kCodecParamAssociatedPayloadType, associated_payload_type); | |
266 return rtx_codec; | |
267 } | |
268 | |
269 VideoCodec::CodecType VideoCodec::GetCodecType() const { | |
270 const char* payload_name = name.c_str(); | |
271 if (_stricmp(payload_name, kRedCodecName) == 0) { | |
272 return CODEC_RED; | |
273 } | |
274 if (_stricmp(payload_name, kUlpfecCodecName) == 0) { | |
275 return CODEC_ULPFEC; | |
276 } | |
277 if (_stricmp(payload_name, kRtxCodecName) == 0) { | |
278 return CODEC_RTX; | |
279 } | |
280 | |
281 return CODEC_VIDEO; | |
282 } | |
283 | |
284 bool VideoCodec::ValidateCodecFormat() const { | |
285 if (id < 0 || id > 127) { | |
286 LOG(LS_ERROR) << "Codec with invalid payload type: " << ToString(); | |
287 return false; | |
288 } | |
289 if (GetCodecType() != CODEC_VIDEO) { | |
290 return true; | |
291 } | |
292 | |
293 // Video validation from here on. | |
294 | |
295 if (width <= 0 || height <= 0) { | |
296 LOG(LS_ERROR) << "Codec with invalid dimensions: " << ToString(); | |
297 return false; | |
298 } | |
299 int min_bitrate = -1; | |
300 int max_bitrate = -1; | |
301 if (GetParam(kCodecParamMinBitrate, &min_bitrate) && | |
302 GetParam(kCodecParamMaxBitrate, &max_bitrate)) { | |
303 if (max_bitrate < min_bitrate) { | |
304 LOG(LS_ERROR) << "Codec with max < min bitrate: " << ToString(); | |
305 return false; | |
306 } | |
307 } | |
308 return true; | |
309 } | |
310 | |
311 DataCodec::DataCodec(int id, const std::string& name, int preference) | |
312 : Codec(id, name, kDataCodecClockrate, preference) { | |
313 } | |
314 | |
315 DataCodec::DataCodec() : Codec() { | |
316 clockrate = kDataCodecClockrate; | |
317 } | |
318 | |
319 DataCodec::DataCodec(const DataCodec& c) = default; | |
320 | |
321 DataCodec& DataCodec::operator=(const DataCodec& c) = default; | |
322 | |
323 std::string DataCodec::ToString() const { | |
324 std::ostringstream os; | |
325 os << "DataCodec[" << id << ":" << name << "]"; | |
326 return os.str(); | |
327 } | |
328 | |
329 bool HasNack(const Codec& codec) { | |
330 return codec.HasFeedbackParam( | |
331 FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); | |
332 } | |
333 | |
334 bool HasRemb(const Codec& codec) { | |
335 return codec.HasFeedbackParam( | |
336 FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); | |
337 } | |
338 | |
339 bool HasTransportCc(const Codec& codec) { | |
340 return codec.HasFeedbackParam( | |
341 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); | |
342 } | |
343 | |
344 bool CodecNamesEq(const std::string& name1, const std::string& name2) { | |
345 return _stricmp(name1.c_str(), name2.c_str()) == 0; | |
346 } | |
347 | |
348 } // namespace cricket | |
OLD | NEW |