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