tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SipccSdpAttributeList.cpp (44869B)


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