1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "sdp/SipccSdpAttributeList.h"
8
9 #include <ostream>
10 #include "mozilla/Assertions.h"
11
12 extern "C" {
13 #include "sdp_private.h"
14 }
15
16 namespace mozilla {
17
18 using InternalResults = SdpParser::InternalResults;
19
20 /* static */
21 const std::string SipccSdpAttributeList::kEmptyString = "";
22
SipccSdpAttributeList(const SipccSdpAttributeList * sessionLevel)23 SipccSdpAttributeList::SipccSdpAttributeList(
24 const SipccSdpAttributeList* sessionLevel)
25 : mSessionLevel(sessionLevel) {
26 memset(&mAttributes, 0, sizeof(mAttributes));
27 }
28
~SipccSdpAttributeList()29 SipccSdpAttributeList::~SipccSdpAttributeList() {
30 for (size_t i = 0; i < kNumAttributeTypes; ++i) {
31 delete mAttributes[i];
32 }
33 }
34
HasAttribute(AttributeType type,bool sessionFallback) const35 bool SipccSdpAttributeList::HasAttribute(AttributeType type,
36 bool sessionFallback) const {
37 return !!GetAttribute(type, sessionFallback);
38 }
39
GetAttribute(AttributeType type,bool sessionFallback) const40 const SdpAttribute* SipccSdpAttributeList::GetAttribute(
41 AttributeType type, bool sessionFallback) const {
42 const SdpAttribute* value = mAttributes[static_cast<size_t>(type)];
43 // Only do fallback when the attribute can appear at both the media and
44 // session level
45 if (!value && !AtSessionLevel() && sessionFallback &&
46 SdpAttribute::IsAllowedAtSessionLevel(type) &&
47 SdpAttribute::IsAllowedAtMediaLevel(type)) {
48 return mSessionLevel->GetAttribute(type, false);
49 }
50 return value;
51 }
52
RemoveAttribute(AttributeType type)53 void SipccSdpAttributeList::RemoveAttribute(AttributeType type) {
54 delete mAttributes[static_cast<size_t>(type)];
55 mAttributes[static_cast<size_t>(type)] = nullptr;
56 }
57
Clear()58 void SipccSdpAttributeList::Clear() {
59 for (size_t i = 0; i < kNumAttributeTypes; ++i) {
60 RemoveAttribute(static_cast<AttributeType>(i));
61 }
62 }
63
Count() const64 uint32_t SipccSdpAttributeList::Count() const {
65 uint32_t count = 0;
66 for (size_t i = 0; i < kNumAttributeTypes; ++i) {
67 if (mAttributes[i]) {
68 count++;
69 }
70 }
71 return count;
72 }
73
SetAttribute(SdpAttribute * attr)74 void SipccSdpAttributeList::SetAttribute(SdpAttribute* attr) {
75 if (!IsAllowedHere(attr->GetType())) {
76 MOZ_ASSERT(false, "This type of attribute is not allowed here");
77 return;
78 }
79 RemoveAttribute(attr->GetType());
80 mAttributes[attr->GetType()] = attr;
81 }
82
LoadSimpleString(sdp_t * sdp,uint16_t level,sdp_attr_e attr,AttributeType targetType,InternalResults & results)83 void SipccSdpAttributeList::LoadSimpleString(sdp_t* sdp, uint16_t level,
84 sdp_attr_e attr,
85 AttributeType targetType,
86 InternalResults& results) {
87 const char* value = sdp_attr_get_simple_string(sdp, attr, level, 0, 1);
88 if (value) {
89 if (!IsAllowedHere(targetType)) {
90 uint32_t lineNumber = sdp_attr_line_number(sdp, attr, level, 0, 1);
91 WarnAboutMisplacedAttribute(targetType, lineNumber, results);
92 } else {
93 SetAttribute(new SdpStringAttribute(targetType, std::string(value)));
94 }
95 }
96 }
97
LoadSimpleStrings(sdp_t * sdp,uint16_t level,InternalResults & results)98 void SipccSdpAttributeList::LoadSimpleStrings(sdp_t* sdp, uint16_t level,
99 InternalResults& results) {
100 LoadSimpleString(sdp, level, SDP_ATTR_MID, SdpAttribute::kMidAttribute,
101 results);
102 LoadSimpleString(sdp, level, SDP_ATTR_LABEL, SdpAttribute::kLabelAttribute,
103 results);
104 }
105
LoadSimpleNumber(sdp_t * sdp,uint16_t level,sdp_attr_e attr,AttributeType targetType,InternalResults & results)106 void SipccSdpAttributeList::LoadSimpleNumber(sdp_t* sdp, uint16_t level,
107 sdp_attr_e attr,
108 AttributeType targetType,
109 InternalResults& results) {
110 if (sdp_attr_valid(sdp, attr, level, 0, 1)) {
111 if (!IsAllowedHere(targetType)) {
112 uint32_t lineNumber = sdp_attr_line_number(sdp, attr, level, 0, 1);
113 WarnAboutMisplacedAttribute(targetType, lineNumber, results);
114 } else {
115 uint32_t value = sdp_attr_get_simple_u32(sdp, attr, level, 0, 1);
116 SetAttribute(new SdpNumberAttribute(targetType, value));
117 }
118 }
119 }
120
LoadSimpleNumbers(sdp_t * sdp,uint16_t level,InternalResults & results)121 void SipccSdpAttributeList::LoadSimpleNumbers(sdp_t* sdp, uint16_t level,
122 InternalResults& results) {
123 LoadSimpleNumber(sdp, level, SDP_ATTR_PTIME, SdpAttribute::kPtimeAttribute,
124 results);
125 LoadSimpleNumber(sdp, level, SDP_ATTR_MAXPTIME,
126 SdpAttribute::kMaxptimeAttribute, results);
127 LoadSimpleNumber(sdp, level, SDP_ATTR_SCTPPORT,
128 SdpAttribute::kSctpPortAttribute, results);
129 LoadSimpleNumber(sdp, level, SDP_ATTR_MAXMESSAGESIZE,
130 SdpAttribute::kMaxMessageSizeAttribute, results);
131 }
132
LoadFlags(sdp_t * sdp,uint16_t level)133 void SipccSdpAttributeList::LoadFlags(sdp_t* sdp, uint16_t level) {
134 if (AtSessionLevel()) {
135 if (sdp_attr_valid(sdp, SDP_ATTR_ICE_LITE, level, 0, 1)) {
136 SetAttribute(new SdpFlagAttribute(SdpAttribute::kIceLiteAttribute));
137 }
138 } else { // media-level
139 if (sdp_attr_valid(sdp, SDP_ATTR_RTCP_MUX, level, 0, 1)) {
140 SetAttribute(new SdpFlagAttribute(SdpAttribute::kRtcpMuxAttribute));
141 }
142 if (sdp_attr_valid(sdp, SDP_ATTR_END_OF_CANDIDATES, level, 0, 1)) {
143 SetAttribute(
144 new SdpFlagAttribute(SdpAttribute::kEndOfCandidatesAttribute));
145 }
146 if (sdp_attr_valid(sdp, SDP_ATTR_BUNDLE_ONLY, level, 0, 1)) {
147 SetAttribute(new SdpFlagAttribute(SdpAttribute::kBundleOnlyAttribute));
148 }
149 if (sdp_attr_valid(sdp, SDP_ATTR_RTCP_RSIZE, level, 0, 1))
150 SetAttribute(new SdpFlagAttribute(SdpAttribute::kRtcpRsizeAttribute));
151 }
152 }
153
ConvertDirection(sdp_direction_e sipcc_direction,SdpDirectionAttribute::Direction * dir_outparam)154 static void ConvertDirection(sdp_direction_e sipcc_direction,
155 SdpDirectionAttribute::Direction* dir_outparam) {
156 switch (sipcc_direction) {
157 case SDP_DIRECTION_SENDRECV:
158 *dir_outparam = SdpDirectionAttribute::kSendrecv;
159 return;
160 case SDP_DIRECTION_SENDONLY:
161 *dir_outparam = SdpDirectionAttribute::kSendonly;
162 return;
163 case SDP_DIRECTION_RECVONLY:
164 *dir_outparam = SdpDirectionAttribute::kRecvonly;
165 return;
166 case SDP_DIRECTION_INACTIVE:
167 *dir_outparam = SdpDirectionAttribute::kInactive;
168 return;
169 case SDP_MAX_QOS_DIRECTIONS:
170 // Nothing actually sets this value.
171 // Fall through to MOZ_CRASH below.
172 {}
173 }
174
175 MOZ_CRASH("Invalid direction from sipcc; this is probably corruption");
176 }
177
LoadDirection(sdp_t * sdp,uint16_t level,InternalResults & results)178 void SipccSdpAttributeList::LoadDirection(sdp_t* sdp, uint16_t level,
179 InternalResults& results) {
180 SdpDirectionAttribute::Direction dir;
181 ConvertDirection(sdp_get_media_direction(sdp, level, 0), &dir);
182 SetAttribute(new SdpDirectionAttribute(dir));
183 }
184
LoadIceAttributes(sdp_t * sdp,uint16_t level)185 void SipccSdpAttributeList::LoadIceAttributes(sdp_t* sdp, uint16_t level) {
186 char* value;
187 sdp_result_e sdpres =
188 sdp_attr_get_ice_attribute(sdp, level, 0, SDP_ATTR_ICE_UFRAG, 1, &value);
189 if (sdpres == SDP_SUCCESS) {
190 SetAttribute(new SdpStringAttribute(SdpAttribute::kIceUfragAttribute,
191 std::string(value)));
192 }
193 sdpres =
194 sdp_attr_get_ice_attribute(sdp, level, 0, SDP_ATTR_ICE_PWD, 1, &value);
195 if (sdpres == SDP_SUCCESS) {
196 SetAttribute(new SdpStringAttribute(SdpAttribute::kIcePwdAttribute,
197 std::string(value)));
198 }
199
200 const char* iceOptVal =
201 sdp_attr_get_simple_string(sdp, SDP_ATTR_ICE_OPTIONS, level, 0, 1);
202 if (iceOptVal) {
203 auto* iceOptions =
204 new SdpOptionsAttribute(SdpAttribute::kIceOptionsAttribute);
205 iceOptions->Load(iceOptVal);
206 SetAttribute(iceOptions);
207 }
208 }
209
LoadFingerprint(sdp_t * sdp,uint16_t level,InternalResults & results)210 bool SipccSdpAttributeList::LoadFingerprint(sdp_t* sdp, uint16_t level,
211 InternalResults& results) {
212 char* value;
213 UniquePtr<SdpFingerprintAttributeList> fingerprintAttrs;
214
215 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
216 sdp_result_e result = sdp_attr_get_dtls_fingerprint_attribute(
217 sdp, level, 0, SDP_ATTR_DTLS_FINGERPRINT, i, &value);
218
219 if (result != SDP_SUCCESS) {
220 break;
221 }
222
223 std::string fingerprintAttr(value);
224 uint32_t lineNumber =
225 sdp_attr_line_number(sdp, SDP_ATTR_DTLS_FINGERPRINT, level, 0, i);
226
227 // sipcc does not expose parse code for this
228 size_t start = fingerprintAttr.find_first_not_of(" \t");
229 if (start == std::string::npos) {
230 results.AddParseError(lineNumber, "Empty fingerprint attribute");
231 return false;
232 }
233
234 size_t end = fingerprintAttr.find_first_of(" \t", start);
235 if (end == std::string::npos) {
236 // One token, no trailing ws
237 results.AddParseError(lineNumber,
238 "Only one token in fingerprint attribute");
239 return false;
240 }
241
242 std::string algorithmToken(fingerprintAttr.substr(start, end - start));
243
244 start = fingerprintAttr.find_first_not_of(" \t", end);
245 if (start == std::string::npos) {
246 // One token, trailing ws
247 results.AddParseError(lineNumber,
248 "Only one token in fingerprint attribute");
249 return false;
250 }
251
252 std::string fingerprintToken(fingerprintAttr.substr(start));
253
254 std::vector<uint8_t> fingerprint =
255 SdpFingerprintAttributeList::ParseFingerprint(fingerprintToken);
256 if (fingerprint.empty()) {
257 results.AddParseError(lineNumber, "Malformed fingerprint token");
258 return false;
259 }
260
261 if (!fingerprintAttrs) {
262 fingerprintAttrs.reset(new SdpFingerprintAttributeList);
263 }
264
265 // Don't assert on unknown algorithm, just skip
266 fingerprintAttrs->PushEntry(algorithmToken, fingerprint, false);
267 }
268
269 if (fingerprintAttrs) {
270 SetAttribute(fingerprintAttrs.release());
271 }
272
273 return true;
274 }
275
LoadCandidate(sdp_t * sdp,uint16_t level)276 void SipccSdpAttributeList::LoadCandidate(sdp_t* sdp, uint16_t level) {
277 char* value;
278 auto candidates =
279 MakeUnique<SdpMultiStringAttribute>(SdpAttribute::kCandidateAttribute);
280
281 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
282 sdp_result_e result = sdp_attr_get_ice_attribute(
283 sdp, level, 0, SDP_ATTR_ICE_CANDIDATE, i, &value);
284
285 if (result != SDP_SUCCESS) {
286 break;
287 }
288
289 candidates->mValues.push_back(value);
290 }
291
292 if (!candidates->mValues.empty()) {
293 SetAttribute(candidates.release());
294 }
295 }
296
LoadSctpmap(sdp_t * sdp,uint16_t level,InternalResults & results)297 bool SipccSdpAttributeList::LoadSctpmap(sdp_t* sdp, uint16_t level,
298 InternalResults& results) {
299 auto sctpmap = MakeUnique<SdpSctpmapAttributeList>();
300 for (uint16_t i = 0; i < UINT16_MAX; ++i) {
301 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SCTPMAP, i + 1);
302
303 if (!attr) {
304 break;
305 }
306
307 // Yeah, this is a little weird, but for now we'll just store this as a
308 // payload type.
309 uint16_t payloadType = attr->attr.sctpmap.port;
310 uint16_t streams = attr->attr.sctpmap.streams;
311 const char* name = attr->attr.sctpmap.protocol;
312
313 std::ostringstream osPayloadType;
314 osPayloadType << payloadType;
315 sctpmap->PushEntry(osPayloadType.str(), name, streams);
316 }
317
318 if (!sctpmap->mSctpmaps.empty()) {
319 SetAttribute(sctpmap.release());
320 }
321
322 return true;
323 }
324
GetCodecType(rtp_ptype type)325 SdpRtpmapAttributeList::CodecType SipccSdpAttributeList::GetCodecType(
326 rtp_ptype type) {
327 switch (type) {
328 case RTP_PCMU:
329 return SdpRtpmapAttributeList::kPCMU;
330 case RTP_PCMA:
331 return SdpRtpmapAttributeList::kPCMA;
332 case RTP_G722:
333 return SdpRtpmapAttributeList::kG722;
334 case RTP_H264_P0:
335 case RTP_H264_P1:
336 return SdpRtpmapAttributeList::kH264;
337 case RTP_OPUS:
338 return SdpRtpmapAttributeList::kOpus;
339 case RTP_VP8:
340 return SdpRtpmapAttributeList::kVP8;
341 case RTP_VP9:
342 return SdpRtpmapAttributeList::kVP9;
343 case RTP_RED:
344 return SdpRtpmapAttributeList::kRed;
345 case RTP_ULPFEC:
346 return SdpRtpmapAttributeList::kUlpfec;
347 case RTP_RTX:
348 return SdpRtpmapAttributeList::kRtx;
349 case RTP_TELEPHONE_EVENT:
350 return SdpRtpmapAttributeList::kTelephoneEvent;
351 case RTP_NONE:
352 // Happens when sipcc doesn't know how to translate to the enum
353 case RTP_CELP:
354 case RTP_G726:
355 case RTP_GSM:
356 case RTP_G723:
357 case RTP_DVI4:
358 case RTP_DVI4_II:
359 case RTP_LPC:
360 case RTP_G728:
361 case RTP_G729:
362 case RTP_JPEG:
363 case RTP_NV:
364 case RTP_H261:
365 case RTP_L16:
366 case RTP_H263:
367 case RTP_ILBC:
368 case RTP_I420:
369 return SdpRtpmapAttributeList::kOtherCodec;
370 }
371 MOZ_CRASH("Invalid codec type from sipcc. Probably corruption.");
372 }
373
LoadRtpmap(sdp_t * sdp,uint16_t level,InternalResults & results)374 bool SipccSdpAttributeList::LoadRtpmap(sdp_t* sdp, uint16_t level,
375 InternalResults& results) {
376 auto rtpmap = MakeUnique<SdpRtpmapAttributeList>();
377 uint16_t count;
378 sdp_result_e result =
379 sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_RTPMAP, &count);
380 if (result != SDP_SUCCESS) {
381 MOZ_ASSERT(false, "Unable to get rtpmap size");
382 results.AddParseError(sdp_get_media_line_number(sdp, level),
383 "Unable to get rtpmap size");
384 return false;
385 }
386 for (uint16_t i = 0; i < count; ++i) {
387 uint16_t pt = sdp_attr_get_rtpmap_payload_type(sdp, level, 0, i + 1);
388 const char* ccName = sdp_attr_get_rtpmap_encname(sdp, level, 0, i + 1);
389
390 if (!ccName) {
391 // Probably no rtpmap attribute for a pt in an m-line
392 results.AddParseError(sdp_get_media_line_number(sdp, level),
393 "No rtpmap attribute for payload type");
394 continue;
395 }
396
397 std::string name(ccName);
398
399 SdpRtpmapAttributeList::CodecType codec =
400 GetCodecType(sdp_get_known_payload_type(sdp, level, pt));
401
402 uint32_t clock = sdp_attr_get_rtpmap_clockrate(sdp, level, 0, i + 1);
403 uint16_t channels = 0;
404
405 // sipcc gives us a channels value of "1" for video
406 if (sdp_get_media_type(sdp, level) == SDP_MEDIA_AUDIO) {
407 channels = sdp_attr_get_rtpmap_num_chan(sdp, level, 0, i + 1);
408 }
409
410 std::ostringstream osPayloadType;
411 osPayloadType << pt;
412 rtpmap->PushEntry(osPayloadType.str(), codec, name, clock, channels);
413 }
414
415 if (!rtpmap->mRtpmaps.empty()) {
416 SetAttribute(rtpmap.release());
417 }
418
419 return true;
420 }
421
LoadSetup(sdp_t * sdp,uint16_t level)422 void SipccSdpAttributeList::LoadSetup(sdp_t* sdp, uint16_t level) {
423 sdp_setup_type_e setupType;
424 auto sdpres = sdp_attr_get_setup_attribute(sdp, level, 0, 1, &setupType);
425
426 if (sdpres != SDP_SUCCESS) {
427 return;
428 }
429
430 switch (setupType) {
431 case SDP_SETUP_ACTIVE:
432 SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kActive));
433 return;
434 case SDP_SETUP_PASSIVE:
435 SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kPassive));
436 return;
437 case SDP_SETUP_ACTPASS:
438 SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kActpass));
439 return;
440 case SDP_SETUP_HOLDCONN:
441 SetAttribute(new SdpSetupAttribute(SdpSetupAttribute::kHoldconn));
442 return;
443 case SDP_SETUP_UNKNOWN:
444 return;
445 case SDP_SETUP_NOT_FOUND:
446 case SDP_MAX_SETUP:
447 // There is no code that will set these.
448 // Fall through to MOZ_CRASH() below.
449 {}
450 }
451
452 MOZ_CRASH("Invalid setup type from sipcc. This is probably corruption.");
453 }
454
LoadSsrc(sdp_t * sdp,uint16_t level)455 void SipccSdpAttributeList::LoadSsrc(sdp_t* sdp, uint16_t level) {
456 auto ssrcs = MakeUnique<SdpSsrcAttributeList>();
457
458 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
459 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SSRC, i);
460
461 if (!attr) {
462 break;
463 }
464
465 sdp_ssrc_t* ssrc = &(attr->attr.ssrc);
466 ssrcs->PushEntry(ssrc->ssrc, ssrc->attribute);
467 }
468
469 if (!ssrcs->mSsrcs.empty()) {
470 SetAttribute(ssrcs.release());
471 }
472 }
473
LoadSsrcGroup(sdp_t * sdp,uint16_t level)474 void SipccSdpAttributeList::LoadSsrcGroup(sdp_t* sdp, uint16_t level) {
475 auto ssrcGroups = MakeUnique<SdpSsrcGroupAttributeList>();
476
477 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
478 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SSRC_GROUP, i);
479
480 if (!attr) {
481 break;
482 }
483
484 sdp_ssrc_group_t* ssrc_group = &(attr->attr.ssrc_group);
485
486 SdpSsrcGroupAttributeList::Semantics semantic;
487 switch (ssrc_group->semantic) {
488 case SDP_SSRC_GROUP_ATTR_FEC:
489 semantic = SdpSsrcGroupAttributeList::kFec;
490 break;
491 case SDP_SSRC_GROUP_ATTR_FID:
492 semantic = SdpSsrcGroupAttributeList::kFid;
493 break;
494 case SDP_SSRC_GROUP_ATTR_FECFR:
495 semantic = SdpSsrcGroupAttributeList::kFecFr;
496 break;
497 case SDP_SSRC_GROUP_ATTR_DUP:
498 semantic = SdpSsrcGroupAttributeList::kDup;
499 break;
500 case SDP_SSRC_GROUP_ATTR_SIM:
501 semantic = SdpSsrcGroupAttributeList::kSim;
502 break;
503 case SDP_MAX_SSRC_GROUP_ATTR_VAL:
504 continue;
505 case SDP_SSRC_GROUP_ATTR_UNSUPPORTED:
506 continue;
507 }
508
509 std::vector<uint32_t> ssrcs;
510 ssrcs.reserve(ssrc_group->num_ssrcs);
511 for (int i = 0; i < ssrc_group->num_ssrcs; ++i) {
512 ssrcs.push_back(ssrc_group->ssrcs[i]);
513 }
514
515 ssrcGroups->PushEntry(semantic, ssrcs);
516 }
517
518 if (!ssrcGroups->mSsrcGroups.empty()) {
519 SetAttribute(ssrcGroups.release());
520 }
521 }
522
LoadImageattr(sdp_t * sdp,uint16_t level,InternalResults & results)523 bool SipccSdpAttributeList::LoadImageattr(sdp_t* sdp, uint16_t level,
524 InternalResults& results) {
525 UniquePtr<SdpImageattrAttributeList> imageattrs(
526 new SdpImageattrAttributeList);
527
528 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
529 const char* imageattrRaw =
530 sdp_attr_get_simple_string(sdp, SDP_ATTR_IMAGEATTR, level, 0, i);
531 if (!imageattrRaw) {
532 break;
533 }
534
535 std::string error;
536 size_t errorPos;
537 if (!imageattrs->PushEntry(imageattrRaw, &error, &errorPos)) {
538 std::ostringstream fullError;
539 fullError << error << " at column " << errorPos;
540 results.AddParseError(
541 sdp_attr_line_number(sdp, SDP_ATTR_IMAGEATTR, level, 0, i),
542 fullError.str());
543 return false;
544 }
545 }
546
547 if (!imageattrs->mImageattrs.empty()) {
548 SetAttribute(imageattrs.release());
549 }
550 return true;
551 }
552
LoadSimulcast(sdp_t * sdp,uint16_t level,InternalResults & results)553 bool SipccSdpAttributeList::LoadSimulcast(sdp_t* sdp, uint16_t level,
554 InternalResults& results) {
555 const char* simulcastRaw =
556 sdp_attr_get_simple_string(sdp, SDP_ATTR_SIMULCAST, level, 0, 1);
557 if (!simulcastRaw) {
558 return true;
559 }
560
561 UniquePtr<SdpSimulcastAttribute> simulcast(new SdpSimulcastAttribute);
562
563 std::istringstream is(simulcastRaw);
564 std::string error;
565 if (!simulcast->Parse(is, &error)) {
566 std::ostringstream fullError;
567 fullError << error << " at column " << is.tellg();
568 results.AddParseError(
569 sdp_attr_line_number(sdp, SDP_ATTR_SIMULCAST, level, 0, 1),
570 fullError.str());
571 return false;
572 }
573
574 SetAttribute(simulcast.release());
575 return true;
576 }
577
LoadGroups(sdp_t * sdp,uint16_t level,InternalResults & results)578 bool SipccSdpAttributeList::LoadGroups(sdp_t* sdp, uint16_t level,
579 InternalResults& results) {
580 uint16_t attrCount = 0;
581 if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_GROUP, &attrCount) !=
582 SDP_SUCCESS) {
583 MOZ_ASSERT(false, "Could not get count of group attributes");
584 results.AddParseError(0, "Could not get count of group attributes");
585 return false;
586 }
587
588 UniquePtr<SdpGroupAttributeList> groups = MakeUnique<SdpGroupAttributeList>();
589 for (uint16_t attr = 1; attr <= attrCount; ++attr) {
590 SdpGroupAttributeList::Semantics semantics;
591 std::vector<std::string> tags;
592
593 switch (sdp_get_group_attr(sdp, level, 0, attr)) {
594 case SDP_GROUP_ATTR_FID:
595 semantics = SdpGroupAttributeList::kFid;
596 break;
597 case SDP_GROUP_ATTR_LS:
598 semantics = SdpGroupAttributeList::kLs;
599 break;
600 case SDP_GROUP_ATTR_ANAT:
601 semantics = SdpGroupAttributeList::kAnat;
602 break;
603 case SDP_GROUP_ATTR_BUNDLE:
604 semantics = SdpGroupAttributeList::kBundle;
605 break;
606 default:
607 continue;
608 }
609
610 uint16_t idCount = sdp_get_group_num_id(sdp, level, 0, attr);
611 for (uint16_t id = 1; id <= idCount; ++id) {
612 const char* idStr = sdp_get_group_id(sdp, level, 0, attr, id);
613 if (!idStr) {
614 std::ostringstream os;
615 os << "bad a=group identifier at " << (attr - 1) << ", " << (id - 1);
616 results.AddParseError(0, os.str());
617 return false;
618 }
619 tags.push_back(std::string(idStr));
620 }
621 groups->PushEntry(semantics, tags);
622 }
623
624 if (!groups->mGroups.empty()) {
625 SetAttribute(groups.release());
626 }
627
628 return true;
629 }
630
LoadMsidSemantics(sdp_t * sdp,uint16_t level,InternalResults & results)631 bool SipccSdpAttributeList::LoadMsidSemantics(sdp_t* sdp, uint16_t level,
632 InternalResults& results) {
633 auto msidSemantics = MakeUnique<SdpMsidSemanticAttributeList>();
634
635 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
636 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_MSID_SEMANTIC, i);
637
638 if (!attr) {
639 break;
640 }
641
642 sdp_msid_semantic_t* msid_semantic = &(attr->attr.msid_semantic);
643 std::vector<std::string> msids;
644 for (size_t i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
645 if (!msid_semantic->msids[i]) {
646 break;
647 }
648
649 msids.push_back(msid_semantic->msids[i]);
650 }
651
652 msidSemantics->PushEntry(msid_semantic->semantic, msids);
653 }
654
655 if (!msidSemantics->mMsidSemantics.empty()) {
656 SetAttribute(msidSemantics.release());
657 }
658 return true;
659 }
660
LoadIdentity(sdp_t * sdp,uint16_t level)661 void SipccSdpAttributeList::LoadIdentity(sdp_t* sdp, uint16_t level) {
662 const char* val =
663 sdp_attr_get_long_string(sdp, SDP_ATTR_IDENTITY, level, 0, 1);
664 if (val) {
665 SetAttribute(new SdpStringAttribute(SdpAttribute::kIdentityAttribute,
666 std::string(val)));
667 }
668 }
669
LoadDtlsMessage(sdp_t * sdp,uint16_t level)670 void SipccSdpAttributeList::LoadDtlsMessage(sdp_t* sdp, uint16_t level) {
671 const char* val =
672 sdp_attr_get_long_string(sdp, SDP_ATTR_DTLS_MESSAGE, level, 0, 1);
673 if (val) {
674 // sipcc does not expose parse code for this, so we use a SDParta-provided
675 // parser
676 std::string strval(val);
677 SetAttribute(new SdpDtlsMessageAttribute(strval));
678 }
679 }
680
LoadFmtp(sdp_t * sdp,uint16_t level)681 void SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level) {
682 auto fmtps = MakeUnique<SdpFmtpAttributeList>();
683
684 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
685 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i);
686
687 if (!attr) {
688 break;
689 }
690
691 sdp_fmtp_t* fmtp = &(attr->attr.fmtp);
692
693 // Get the payload type
694 std::stringstream osPayloadType;
695 // payload_num is the number in the fmtp attribute, verbatim
696 osPayloadType << fmtp->payload_num;
697
698 // Get parsed form of parameters, if supported
699 UniquePtr<SdpFmtpAttributeList::Parameters> parameters;
700
701 rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num);
702
703 switch (codec) {
704 case RTP_H264_P0:
705 case RTP_H264_P1: {
706 SdpFmtpAttributeList::H264Parameters* h264Parameters(
707 new SdpFmtpAttributeList::H264Parameters);
708
709 sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets,
710 sizeof(h264Parameters->sprop_parameter_sets));
711
712 h264Parameters->level_asymmetry_allowed =
713 !!(fmtp->level_asymmetry_allowed);
714
715 h264Parameters->packetization_mode = fmtp->packetization_mode;
716 sscanf(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id);
717 h264Parameters->max_mbps = fmtp->max_mbps;
718 h264Parameters->max_fs = fmtp->max_fs;
719 h264Parameters->max_cpb = fmtp->max_cpb;
720 h264Parameters->max_dpb = fmtp->max_dpb;
721 h264Parameters->max_br = fmtp->max_br;
722
723 parameters.reset(h264Parameters);
724 } break;
725 case RTP_VP9: {
726 SdpFmtpAttributeList::VP8Parameters* vp9Parameters(
727 new SdpFmtpAttributeList::VP8Parameters(
728 SdpRtpmapAttributeList::kVP9));
729
730 vp9Parameters->max_fs = fmtp->max_fs;
731 vp9Parameters->max_fr = fmtp->max_fr;
732
733 parameters.reset(vp9Parameters);
734 } break;
735 case RTP_VP8: {
736 SdpFmtpAttributeList::VP8Parameters* vp8Parameters(
737 new SdpFmtpAttributeList::VP8Parameters(
738 SdpRtpmapAttributeList::kVP8));
739
740 vp8Parameters->max_fs = fmtp->max_fs;
741 vp8Parameters->max_fr = fmtp->max_fr;
742
743 parameters.reset(vp8Parameters);
744 } break;
745 case RTP_RED: {
746 SdpFmtpAttributeList::RedParameters* redParameters(
747 new SdpFmtpAttributeList::RedParameters);
748 for (int i = 0; i < SDP_FMTP_MAX_REDUNDANT_ENCODINGS &&
749 fmtp->redundant_encodings[i];
750 ++i) {
751 redParameters->encodings.push_back(fmtp->redundant_encodings[i]);
752 }
753
754 parameters.reset(redParameters);
755 } break;
756 case RTP_OPUS: {
757 SdpFmtpAttributeList::OpusParameters* opusParameters(
758 new SdpFmtpAttributeList::OpusParameters);
759 opusParameters->maxplaybackrate = fmtp->maxplaybackrate;
760 opusParameters->stereo = fmtp->stereo;
761 opusParameters->useInBandFec = fmtp->useinbandfec;
762 opusParameters->maxAverageBitrate = fmtp->maxaveragebitrate;
763 opusParameters->useDTX = fmtp->usedtx;
764 parameters.reset(opusParameters);
765 } break;
766 case RTP_TELEPHONE_EVENT: {
767 SdpFmtpAttributeList::TelephoneEventParameters* teParameters(
768 new SdpFmtpAttributeList::TelephoneEventParameters);
769 if (strlen(fmtp->dtmf_tones) > 0) {
770 teParameters->dtmfTones = fmtp->dtmf_tones;
771 }
772 parameters.reset(teParameters);
773 } break;
774 case RTP_RTX: {
775 SdpFmtpAttributeList::RtxParameters* rtxParameters(
776 new SdpFmtpAttributeList::RtxParameters);
777 rtxParameters->apt = fmtp->apt;
778 if (fmtp->has_rtx_time == TRUE) {
779 rtxParameters->rtx_time = Some(fmtp->rtx_time);
780 }
781 parameters.reset(rtxParameters);
782 } break;
783 default: {
784 }
785 }
786
787 fmtps->PushEntry(osPayloadType.str(), std::move(parameters));
788 }
789
790 if (!fmtps->mFmtps.empty()) {
791 SetAttribute(fmtps.release());
792 }
793 }
794
LoadMsids(sdp_t * sdp,uint16_t level,InternalResults & results)795 void SipccSdpAttributeList::LoadMsids(sdp_t* sdp, uint16_t level,
796 InternalResults& results) {
797 uint16_t attrCount = 0;
798 if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_MSID, &attrCount) !=
799 SDP_SUCCESS) {
800 MOZ_ASSERT(false, "Unable to get count of msid attributes");
801 results.AddParseError(0, "Unable to get count of msid attributes");
802 return;
803 }
804 auto msids = MakeUnique<SdpMsidAttributeList>();
805 for (uint16_t i = 1; i <= attrCount; ++i) {
806 uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_MSID, level, 0, i);
807
808 const char* identifier = sdp_attr_get_msid_identifier(sdp, level, 0, i);
809 if (!identifier) {
810 results.AddParseError(lineNumber, "msid attribute with bad identity");
811 continue;
812 }
813
814 const char* appdata = sdp_attr_get_msid_appdata(sdp, level, 0, i);
815 if (!appdata) {
816 results.AddParseError(lineNumber, "msid attribute with bad appdata");
817 continue;
818 }
819
820 msids->PushEntry(identifier, appdata);
821 }
822
823 if (!msids->mMsids.empty()) {
824 SetAttribute(msids.release());
825 }
826 }
827
LoadRid(sdp_t * sdp,uint16_t level,InternalResults & results)828 bool SipccSdpAttributeList::LoadRid(sdp_t* sdp, uint16_t level,
829 InternalResults& results) {
830 UniquePtr<SdpRidAttributeList> rids(new SdpRidAttributeList);
831
832 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
833 const char* ridRaw =
834 sdp_attr_get_simple_string(sdp, SDP_ATTR_RID, level, 0, i);
835 if (!ridRaw) {
836 break;
837 }
838
839 std::string error;
840 size_t errorPos;
841 if (!rids->PushEntry(ridRaw, &error, &errorPos)) {
842 std::ostringstream fullError;
843 fullError << error << " at column " << errorPos;
844 results.AddParseError(
845 sdp_attr_line_number(sdp, SDP_ATTR_RID, level, 0, i),
846 fullError.str());
847 return false;
848 }
849 }
850
851 if (!rids->mRids.empty()) {
852 SetAttribute(rids.release());
853 }
854 return true;
855 }
856
LoadExtmap(sdp_t * sdp,uint16_t level,InternalResults & results)857 void SipccSdpAttributeList::LoadExtmap(sdp_t* sdp, uint16_t level,
858 InternalResults& results) {
859 auto extmaps = MakeUnique<SdpExtmapAttributeList>();
860
861 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
862 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_EXTMAP, i);
863
864 if (!attr) {
865 break;
866 }
867
868 sdp_extmap_t* extmap = &(attr->attr.extmap);
869
870 SdpDirectionAttribute::Direction dir = SdpDirectionAttribute::kSendrecv;
871
872 if (extmap->media_direction_specified) {
873 ConvertDirection(extmap->media_direction, &dir);
874 }
875
876 extmaps->PushEntry(extmap->id, dir, extmap->media_direction_specified,
877 extmap->uri, extmap->extension_attributes);
878 }
879
880 if (!extmaps->mExtmaps.empty()) {
881 if (!AtSessionLevel() &&
882 mSessionLevel->HasAttribute(SdpAttribute::kExtmapAttribute)) {
883 uint32_t lineNumber =
884 sdp_attr_line_number(sdp, SDP_ATTR_EXTMAP, level, 0, 1);
885 results.AddParseError(
886 lineNumber, "extmap attributes in both session and media level");
887 }
888 SetAttribute(extmaps.release());
889 }
890 }
891
LoadRtcpFb(sdp_t * sdp,uint16_t level,InternalResults & results)892 void SipccSdpAttributeList::LoadRtcpFb(sdp_t* sdp, uint16_t level,
893 InternalResults& results) {
894 auto rtcpfbs = MakeUnique<SdpRtcpFbAttributeList>();
895
896 for (uint16_t i = 1; i < UINT16_MAX; ++i) {
897 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_RTCP_FB, i);
898
899 if (!attr) {
900 break;
901 }
902
903 sdp_fmtp_fb_t* rtcpfb = &attr->attr.rtcp_fb;
904
905 SdpRtcpFbAttributeList::Type type;
906 std::string parameter;
907
908 // Set type and parameter
909 switch (rtcpfb->feedback_type) {
910 case SDP_RTCP_FB_ACK:
911 type = SdpRtcpFbAttributeList::kAck;
912 switch (rtcpfb->param.ack) {
913 // TODO: sipcc doesn't seem to support ack with no following token.
914 // Issue 189.
915 case SDP_RTCP_FB_ACK_RPSI:
916 parameter = SdpRtcpFbAttributeList::rpsi;
917 break;
918 case SDP_RTCP_FB_ACK_APP:
919 parameter = SdpRtcpFbAttributeList::app;
920 break;
921 default:
922 // Type we don't care about, ignore.
923 continue;
924 }
925 break;
926 case SDP_RTCP_FB_CCM:
927 type = SdpRtcpFbAttributeList::kCcm;
928 switch (rtcpfb->param.ccm) {
929 case SDP_RTCP_FB_CCM_FIR:
930 parameter = SdpRtcpFbAttributeList::fir;
931 break;
932 case SDP_RTCP_FB_CCM_TMMBR:
933 parameter = SdpRtcpFbAttributeList::tmmbr;
934 break;
935 case SDP_RTCP_FB_CCM_TSTR:
936 parameter = SdpRtcpFbAttributeList::tstr;
937 break;
938 case SDP_RTCP_FB_CCM_VBCM:
939 parameter = SdpRtcpFbAttributeList::vbcm;
940 break;
941 default:
942 // Type we don't care about, ignore.
943 continue;
944 }
945 break;
946 case SDP_RTCP_FB_NACK:
947 type = SdpRtcpFbAttributeList::kNack;
948 switch (rtcpfb->param.nack) {
949 case SDP_RTCP_FB_NACK_BASIC:
950 break;
951 case SDP_RTCP_FB_NACK_SLI:
952 parameter = SdpRtcpFbAttributeList::sli;
953 break;
954 case SDP_RTCP_FB_NACK_PLI:
955 parameter = SdpRtcpFbAttributeList::pli;
956 break;
957 case SDP_RTCP_FB_NACK_RPSI:
958 parameter = SdpRtcpFbAttributeList::rpsi;
959 break;
960 case SDP_RTCP_FB_NACK_APP:
961 parameter = SdpRtcpFbAttributeList::app;
962 break;
963 default:
964 // Type we don't care about, ignore.
965 continue;
966 }
967 break;
968 case SDP_RTCP_FB_TRR_INT: {
969 type = SdpRtcpFbAttributeList::kTrrInt;
970 std::ostringstream os;
971 os << rtcpfb->param.trr_int;
972 parameter = os.str();
973 } break;
974 case SDP_RTCP_FB_REMB: {
975 type = SdpRtcpFbAttributeList::kRemb;
976 } break;
977 case SDP_RTCP_FB_TRANSPORT_CC: {
978 type = SdpRtcpFbAttributeList::kTransportCC;
979 } break;
980 default:
981 // Type we don't care about, ignore.
982 continue;
983 }
984
985 std::stringstream osPayloadType;
986 if (rtcpfb->payload_num == UINT16_MAX) {
987 osPayloadType << "*";
988 } else {
989 osPayloadType << rtcpfb->payload_num;
990 }
991
992 std::string pt(osPayloadType.str());
993 std::string extra(rtcpfb->extra);
994
995 rtcpfbs->PushEntry(pt, type, parameter, extra);
996 }
997
998 if (!rtcpfbs->mFeedbacks.empty()) {
999 SetAttribute(rtcpfbs.release());
1000 }
1001 }
1002
LoadRtcp(sdp_t * sdp,uint16_t level,InternalResults & results)1003 void SipccSdpAttributeList::LoadRtcp(sdp_t* sdp, uint16_t level,
1004 InternalResults& results) {
1005 sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_RTCP, 1);
1006
1007 if (!attr) {
1008 return;
1009 }
1010
1011 sdp_rtcp_t* rtcp = &attr->attr.rtcp;
1012
1013 if (rtcp->nettype != SDP_NT_INTERNET) {
1014 return;
1015 }
1016
1017 if (rtcp->addrtype != SDP_AT_IP4 && rtcp->addrtype != SDP_AT_IP6) {
1018 return;
1019 }
1020
1021 if (!strlen(rtcp->addr)) {
1022 SetAttribute(new SdpRtcpAttribute(rtcp->port));
1023 } else {
1024 SetAttribute(new SdpRtcpAttribute(
1025 rtcp->port, sdp::kInternet,
1026 rtcp->addrtype == SDP_AT_IP4 ? sdp::kIPv4 : sdp::kIPv6, rtcp->addr));
1027 }
1028 }
1029
Load(sdp_t * sdp,uint16_t level,InternalResults & results)1030 bool SipccSdpAttributeList::Load(sdp_t* sdp, uint16_t level,
1031 InternalResults& results) {
1032 LoadSimpleStrings(sdp, level, results);
1033 LoadSimpleNumbers(sdp, level, results);
1034 LoadFlags(sdp, level);
1035 LoadDirection(sdp, level, results);
1036
1037 if (AtSessionLevel()) {
1038 if (!LoadGroups(sdp, level, results)) {
1039 return false;
1040 }
1041
1042 if (!LoadMsidSemantics(sdp, level, results)) {
1043 return false;
1044 }
1045
1046 LoadIdentity(sdp, level);
1047 LoadDtlsMessage(sdp, level);
1048 } else {
1049 sdp_media_e mtype = sdp_get_media_type(sdp, level);
1050 if (mtype == SDP_MEDIA_APPLICATION) {
1051 LoadSctpmap(sdp, level, results);
1052 } else {
1053 if (!LoadRtpmap(sdp, level, results)) {
1054 return false;
1055 }
1056 }
1057 LoadCandidate(sdp, level);
1058 LoadFmtp(sdp, level);
1059 LoadMsids(sdp, level, results);
1060 LoadRtcpFb(sdp, level, results);
1061 LoadRtcp(sdp, level, results);
1062 LoadSsrc(sdp, level);
1063 LoadSsrcGroup(sdp, level);
1064 if (!LoadImageattr(sdp, level, results)) {
1065 return false;
1066 }
1067 if (!LoadSimulcast(sdp, level, results)) {
1068 return false;
1069 }
1070 if (!LoadRid(sdp, level, results)) {
1071 return false;
1072 }
1073 }
1074
1075 LoadIceAttributes(sdp, level);
1076 if (!LoadFingerprint(sdp, level, results)) {
1077 return false;
1078 }
1079 LoadSetup(sdp, level);
1080 LoadExtmap(sdp, level, results);
1081
1082 return true;
1083 }
1084
IsAllowedHere(SdpAttribute::AttributeType type) const1085 bool SipccSdpAttributeList::IsAllowedHere(
1086 SdpAttribute::AttributeType type) const {
1087 if (AtSessionLevel() && !SdpAttribute::IsAllowedAtSessionLevel(type)) {
1088 return false;
1089 }
1090
1091 if (!AtSessionLevel() && !SdpAttribute::IsAllowedAtMediaLevel(type)) {
1092 return false;
1093 }
1094
1095 return true;
1096 }
1097
WarnAboutMisplacedAttribute(SdpAttribute::AttributeType type,uint32_t lineNumber,InternalResults & results)1098 void SipccSdpAttributeList::WarnAboutMisplacedAttribute(
1099 SdpAttribute::AttributeType type, uint32_t lineNumber,
1100 InternalResults& results) {
1101 std::string warning = SdpAttribute::GetAttributeTypeString(type) +
1102 (AtSessionLevel() ? " at session level. Ignoring."
1103 : " at media level. Ignoring.");
1104 results.AddParseError(lineNumber, warning);
1105 }
1106
GetCandidate() const1107 const std::vector<std::string>& SipccSdpAttributeList::GetCandidate() const {
1108 if (!HasAttribute(SdpAttribute::kCandidateAttribute)) {
1109 MOZ_CRASH();
1110 }
1111
1112 return static_cast<const SdpMultiStringAttribute*>(
1113 GetAttribute(SdpAttribute::kCandidateAttribute))
1114 ->mValues;
1115 }
1116
GetConnection() const1117 const SdpConnectionAttribute& SipccSdpAttributeList::GetConnection() const {
1118 if (!HasAttribute(SdpAttribute::kConnectionAttribute)) {
1119 MOZ_CRASH();
1120 }
1121
1122 return *static_cast<const SdpConnectionAttribute*>(
1123 GetAttribute(SdpAttribute::kConnectionAttribute));
1124 }
1125
GetDirection() const1126 SdpDirectionAttribute::Direction SipccSdpAttributeList::GetDirection() const {
1127 if (!HasAttribute(SdpAttribute::kDirectionAttribute)) {
1128 MOZ_CRASH();
1129 }
1130
1131 const SdpAttribute* attr = GetAttribute(SdpAttribute::kDirectionAttribute);
1132 return static_cast<const SdpDirectionAttribute*>(attr)->mValue;
1133 }
1134
GetDtlsMessage() const1135 const SdpDtlsMessageAttribute& SipccSdpAttributeList::GetDtlsMessage() const {
1136 if (!HasAttribute(SdpAttribute::kDtlsMessageAttribute)) {
1137 MOZ_CRASH();
1138 }
1139 const SdpAttribute* attr = GetAttribute(SdpAttribute::kDtlsMessageAttribute);
1140 return *static_cast<const SdpDtlsMessageAttribute*>(attr);
1141 }
1142
GetExtmap() const1143 const SdpExtmapAttributeList& SipccSdpAttributeList::GetExtmap() const {
1144 if (!HasAttribute(SdpAttribute::kExtmapAttribute)) {
1145 MOZ_CRASH();
1146 }
1147
1148 return *static_cast<const SdpExtmapAttributeList*>(
1149 GetAttribute(SdpAttribute::kExtmapAttribute));
1150 }
1151
GetFingerprint() const1152 const SdpFingerprintAttributeList& SipccSdpAttributeList::GetFingerprint()
1153 const {
1154 if (!HasAttribute(SdpAttribute::kFingerprintAttribute)) {
1155 MOZ_CRASH();
1156 }
1157 const SdpAttribute* attr = GetAttribute(SdpAttribute::kFingerprintAttribute);
1158 return *static_cast<const SdpFingerprintAttributeList*>(attr);
1159 }
1160
GetFmtp() const1161 const SdpFmtpAttributeList& SipccSdpAttributeList::GetFmtp() const {
1162 if (!HasAttribute(SdpAttribute::kFmtpAttribute)) {
1163 MOZ_CRASH();
1164 }
1165
1166 return *static_cast<const SdpFmtpAttributeList*>(
1167 GetAttribute(SdpAttribute::kFmtpAttribute));
1168 }
1169
GetGroup() const1170 const SdpGroupAttributeList& SipccSdpAttributeList::GetGroup() const {
1171 if (!HasAttribute(SdpAttribute::kGroupAttribute)) {
1172 MOZ_CRASH();
1173 }
1174
1175 return *static_cast<const SdpGroupAttributeList*>(
1176 GetAttribute(SdpAttribute::kGroupAttribute));
1177 }
1178
GetIceOptions() const1179 const SdpOptionsAttribute& SipccSdpAttributeList::GetIceOptions() const {
1180 if (!HasAttribute(SdpAttribute::kIceOptionsAttribute)) {
1181 MOZ_CRASH();
1182 }
1183
1184 const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceOptionsAttribute);
1185 return *static_cast<const SdpOptionsAttribute*>(attr);
1186 }
1187
GetIcePwd() const1188 const std::string& SipccSdpAttributeList::GetIcePwd() const {
1189 if (!HasAttribute(SdpAttribute::kIcePwdAttribute)) {
1190 return kEmptyString;
1191 }
1192 const SdpAttribute* attr = GetAttribute(SdpAttribute::kIcePwdAttribute);
1193 return static_cast<const SdpStringAttribute*>(attr)->mValue;
1194 }
1195
GetIceUfrag() const1196 const std::string& SipccSdpAttributeList::GetIceUfrag() const {
1197 if (!HasAttribute(SdpAttribute::kIceUfragAttribute)) {
1198 return kEmptyString;
1199 }
1200 const SdpAttribute* attr = GetAttribute(SdpAttribute::kIceUfragAttribute);
1201 return static_cast<const SdpStringAttribute*>(attr)->mValue;
1202 }
1203
GetIdentity() const1204 const std::string& SipccSdpAttributeList::GetIdentity() const {
1205 if (!HasAttribute(SdpAttribute::kIdentityAttribute)) {
1206 return kEmptyString;
1207 }
1208 const SdpAttribute* attr = GetAttribute(SdpAttribute::kIdentityAttribute);
1209 return static_cast<const SdpStringAttribute*>(attr)->mValue;
1210 }
1211
GetImageattr() const1212 const SdpImageattrAttributeList& SipccSdpAttributeList::GetImageattr() const {
1213 if (!HasAttribute(SdpAttribute::kImageattrAttribute)) {
1214 MOZ_CRASH();
1215 }
1216 const SdpAttribute* attr = GetAttribute(SdpAttribute::kImageattrAttribute);
1217 return *static_cast<const SdpImageattrAttributeList*>(attr);
1218 }
1219
GetSimulcast() const1220 const SdpSimulcastAttribute& SipccSdpAttributeList::GetSimulcast() const {
1221 if (!HasAttribute(SdpAttribute::kSimulcastAttribute)) {
1222 MOZ_CRASH();
1223 }
1224 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSimulcastAttribute);
1225 return *static_cast<const SdpSimulcastAttribute*>(attr);
1226 }
1227
GetLabel() const1228 const std::string& SipccSdpAttributeList::GetLabel() const {
1229 if (!HasAttribute(SdpAttribute::kLabelAttribute)) {
1230 return kEmptyString;
1231 }
1232 const SdpAttribute* attr = GetAttribute(SdpAttribute::kLabelAttribute);
1233 return static_cast<const SdpStringAttribute*>(attr)->mValue;
1234 }
1235
GetMaxptime() const1236 uint32_t SipccSdpAttributeList::GetMaxptime() const {
1237 if (!HasAttribute(SdpAttribute::kMaxptimeAttribute)) {
1238 MOZ_CRASH();
1239 }
1240 const SdpAttribute* attr = GetAttribute(SdpAttribute::kMaxptimeAttribute);
1241 return static_cast<const SdpNumberAttribute*>(attr)->mValue;
1242 }
1243
GetMid() const1244 const std::string& SipccSdpAttributeList::GetMid() const {
1245 if (!HasAttribute(SdpAttribute::kMidAttribute)) {
1246 return kEmptyString;
1247 }
1248 const SdpAttribute* attr = GetAttribute(SdpAttribute::kMidAttribute);
1249 return static_cast<const SdpStringAttribute*>(attr)->mValue;
1250 }
1251
GetMsid() const1252 const SdpMsidAttributeList& SipccSdpAttributeList::GetMsid() const {
1253 if (!HasAttribute(SdpAttribute::kMsidAttribute)) {
1254 MOZ_CRASH();
1255 }
1256 const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidAttribute);
1257 return *static_cast<const SdpMsidAttributeList*>(attr);
1258 }
1259
GetMsidSemantic() const1260 const SdpMsidSemanticAttributeList& SipccSdpAttributeList::GetMsidSemantic()
1261 const {
1262 if (!HasAttribute(SdpAttribute::kMsidSemanticAttribute)) {
1263 MOZ_CRASH();
1264 }
1265 const SdpAttribute* attr = GetAttribute(SdpAttribute::kMsidSemanticAttribute);
1266 return *static_cast<const SdpMsidSemanticAttributeList*>(attr);
1267 }
1268
GetRid() const1269 const SdpRidAttributeList& SipccSdpAttributeList::GetRid() const {
1270 if (!HasAttribute(SdpAttribute::kRidAttribute)) {
1271 MOZ_CRASH();
1272 }
1273 const SdpAttribute* attr = GetAttribute(SdpAttribute::kRidAttribute);
1274 return *static_cast<const SdpRidAttributeList*>(attr);
1275 }
1276
GetPtime() const1277 uint32_t SipccSdpAttributeList::GetPtime() const {
1278 if (!HasAttribute(SdpAttribute::kPtimeAttribute)) {
1279 MOZ_CRASH();
1280 }
1281 const SdpAttribute* attr = GetAttribute(SdpAttribute::kPtimeAttribute);
1282 return static_cast<const SdpNumberAttribute*>(attr)->mValue;
1283 }
1284
GetRtcp() const1285 const SdpRtcpAttribute& SipccSdpAttributeList::GetRtcp() const {
1286 if (!HasAttribute(SdpAttribute::kRtcpAttribute)) {
1287 MOZ_CRASH();
1288 }
1289 const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpAttribute);
1290 return *static_cast<const SdpRtcpAttribute*>(attr);
1291 }
1292
GetRtcpFb() const1293 const SdpRtcpFbAttributeList& SipccSdpAttributeList::GetRtcpFb() const {
1294 if (!HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
1295 MOZ_CRASH();
1296 }
1297 const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtcpFbAttribute);
1298 return *static_cast<const SdpRtcpFbAttributeList*>(attr);
1299 }
1300
GetRemoteCandidates() const1301 const SdpRemoteCandidatesAttribute& SipccSdpAttributeList::GetRemoteCandidates()
1302 const {
1303 MOZ_CRASH("Not yet implemented");
1304 }
1305
GetRtpmap() const1306 const SdpRtpmapAttributeList& SipccSdpAttributeList::GetRtpmap() const {
1307 if (!HasAttribute(SdpAttribute::kRtpmapAttribute)) {
1308 MOZ_CRASH();
1309 }
1310 const SdpAttribute* attr = GetAttribute(SdpAttribute::kRtpmapAttribute);
1311 return *static_cast<const SdpRtpmapAttributeList*>(attr);
1312 }
1313
GetSctpmap() const1314 const SdpSctpmapAttributeList& SipccSdpAttributeList::GetSctpmap() const {
1315 if (!HasAttribute(SdpAttribute::kSctpmapAttribute)) {
1316 MOZ_CRASH();
1317 }
1318 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpmapAttribute);
1319 return *static_cast<const SdpSctpmapAttributeList*>(attr);
1320 }
1321
GetSctpPort() const1322 uint32_t SipccSdpAttributeList::GetSctpPort() const {
1323 if (!HasAttribute(SdpAttribute::kSctpPortAttribute)) {
1324 MOZ_CRASH();
1325 }
1326
1327 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSctpPortAttribute);
1328 return static_cast<const SdpNumberAttribute*>(attr)->mValue;
1329 }
1330
GetMaxMessageSize() const1331 uint32_t SipccSdpAttributeList::GetMaxMessageSize() const {
1332 if (!HasAttribute(SdpAttribute::kMaxMessageSizeAttribute)) {
1333 MOZ_CRASH();
1334 }
1335
1336 const SdpAttribute* attr =
1337 GetAttribute(SdpAttribute::kMaxMessageSizeAttribute);
1338 return static_cast<const SdpNumberAttribute*>(attr)->mValue;
1339 }
1340
GetSetup() const1341 const SdpSetupAttribute& SipccSdpAttributeList::GetSetup() const {
1342 if (!HasAttribute(SdpAttribute::kSetupAttribute)) {
1343 MOZ_CRASH();
1344 }
1345 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSetupAttribute);
1346 return *static_cast<const SdpSetupAttribute*>(attr);
1347 }
1348
GetSsrc() const1349 const SdpSsrcAttributeList& SipccSdpAttributeList::GetSsrc() const {
1350 if (!HasAttribute(SdpAttribute::kSsrcAttribute)) {
1351 MOZ_CRASH();
1352 }
1353 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSsrcAttribute);
1354 return *static_cast<const SdpSsrcAttributeList*>(attr);
1355 }
1356
GetSsrcGroup() const1357 const SdpSsrcGroupAttributeList& SipccSdpAttributeList::GetSsrcGroup() const {
1358 if (!HasAttribute(SdpAttribute::kSsrcGroupAttribute)) {
1359 MOZ_CRASH();
1360 }
1361 const SdpAttribute* attr = GetAttribute(SdpAttribute::kSsrcGroupAttribute);
1362 return *static_cast<const SdpSsrcGroupAttributeList*>(attr);
1363 }
1364
Serialize(std::ostream & os) const1365 void SipccSdpAttributeList::Serialize(std::ostream& os) const {
1366 for (size_t i = 0; i < kNumAttributeTypes; ++i) {
1367 if (mAttributes[i]) {
1368 os << *mAttributes[i];
1369 }
1370 }
1371 }
1372
1373 } // namespace mozilla
1374