Beispiel #1
0
nsresult
SdpHelper::GetIdsFromMsid(const Sdp& sdp,
                                const SdpMediaSection& msection,
                                std::string* streamId,
                                std::string* trackId)
{
  if (!sdp.GetAttributeList().HasAttribute(
        SdpAttribute::kMsidSemanticAttribute)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  auto& msidSemantics = sdp.GetAttributeList().GetMsidSemantic().mMsidSemantics;
  std::vector<SdpMsidAttributeList::Msid> allMsids;
  nsresult rv = GetMsids(msection, &allMsids);
  NS_ENSURE_SUCCESS(rv, rv);

  bool allMsidsAreWebrtc = false;
  std::set<std::string> webrtcMsids;

  for (auto i = msidSemantics.begin(); i != msidSemantics.end(); ++i) {
    if (i->semantic == "WMS") {
      for (auto j = i->msids.begin(); j != i->msids.end(); ++j) {
        if (*j == "*") {
          allMsidsAreWebrtc = true;
        } else {
          webrtcMsids.insert(*j);
        }
      }
      break;
    }
  }

  bool found = false;

  for (auto i = allMsids.begin(); i != allMsids.end(); ++i) {
    if (allMsidsAreWebrtc || webrtcMsids.count(i->identifier)) {
      if (i->appdata.empty()) {
        SDP_SET_ERROR("Invalid webrtc msid at level " << msection.GetLevel()
                       << ": Missing track id.");
        return NS_ERROR_INVALID_ARG;
      }
      if (!found) {
        *streamId = i->identifier;
        *trackId = i->appdata;
        found = true;
      } else if ((*streamId != i->identifier) || (*trackId != i->appdata)) {
        SDP_SET_ERROR("Found multiple different webrtc msids in m-section "
                       << msection.GetLevel() << ". The behavior here is "
                       "undefined.");
        return NS_ERROR_INVALID_ARG;
      }
    }
  }

  if (!found) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  return NS_OK;
}
Beispiel #2
0
nsresult
SdpHelper::AddCandidateToSdp(Sdp* sdp,
                             const std::string& candidateUntrimmed,
                             const std::string& mid,
                             uint16_t level)
{

  if (level >= sdp->GetMediaSectionCount()) {
    SDP_SET_ERROR("Index " << level << " out of range");
    return NS_ERROR_INVALID_ARG;
  }

  // Trim off '[a=]candidate:'
  size_t begin = candidateUntrimmed.find(':');
  if (begin == std::string::npos) {
    SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")");
    return NS_ERROR_INVALID_ARG;
  }
  ++begin;

  std::string candidate = candidateUntrimmed.substr(begin);

  // TODO(bug 1095793): mid

  SdpMediaSection& msection = sdp->GetMediaSection(level);
  SdpAttributeList& attrList = msection.GetAttributeList();

  UniquePtr<SdpMultiStringAttribute> candidates;
  if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) {
    // Create new
    candidates.reset(
        new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
  } else {
    // Copy existing
    candidates.reset(new SdpMultiStringAttribute(
        *static_cast<const SdpMultiStringAttribute*>(
            attrList.GetAttribute(SdpAttribute::kCandidateAttribute))));
  }
  candidates->PushEntry(candidate);
  attrList.SetAttribute(candidates.release());

  return NS_OK;
}
Beispiel #3
0
nsresult
SdpHelper::GetComponent(const std::string& candidate, size_t* component)
{
  unsigned int temp;
  int32_t result = PR_sscanf(candidate.c_str(), "%*s %u", &temp);
  if (result == 1) {
    *component = temp;
    return NS_OK;
  }
  SDP_SET_ERROR("Malformed ICE candidate: " << candidate);
  return NS_ERROR_INVALID_ARG;
}
Beispiel #4
0
nsresult
SdpHelper::GetBundledMids(const Sdp& sdp, BundledMids* bundledMids)
{
  std::vector<SdpGroupAttributeList::Group> bundleGroups;
  GetBundleGroups(sdp, &bundleGroups);

  for (SdpGroupAttributeList::Group& group : bundleGroups) {
    if (group.tags.empty()) {
      SDP_SET_ERROR("Empty BUNDLE group");
      return NS_ERROR_INVALID_ARG;
    }

    const SdpMediaSection* masterBundleMsection(
        FindMsectionByMid(sdp, group.tags[0]));

    if (!masterBundleMsection) {
      SDP_SET_ERROR("mid specified for bundle transport in group attribute"
          " does not exist in the SDP. (mid=" << group.tags[0] << ")");
      return NS_ERROR_INVALID_ARG;
    }

    if (MsectionIsDisabled(*masterBundleMsection)) {
      SDP_SET_ERROR("mid specified for bundle transport in group attribute"
          " points at a disabled m-section. (mid=" << group.tags[0] << ")");
      return NS_ERROR_INVALID_ARG;
    }

    for (const std::string& mid : group.tags) {
      if (bundledMids->count(mid)) {
        SDP_SET_ERROR("mid \'" << mid << "\' appears more than once in a "
                       "BUNDLE group");
        return NS_ERROR_INVALID_ARG;
      }

      (*bundledMids)[mid] = masterBundleMsection;
    }
  }

  return NS_OK;
}
Beispiel #5
0
nsresult
SdpHelper::GetMidFromLevel(const Sdp& sdp,
                           uint16_t level,
                           std::string* mid)
{
  if (level >= sdp.GetMediaSectionCount()) {
    SDP_SET_ERROR("Index " << level << " out of range");
    return NS_ERROR_INVALID_ARG;
  }

  const SdpMediaSection& msection = sdp.GetMediaSection(level);
  const SdpAttributeList& attrList = msection.GetAttributeList();

  // grab the mid and set the outparam
  if (attrList.HasAttribute(SdpAttribute::kMidAttribute)) {
    *mid = attrList.GetMid();
  }

  return NS_OK;
}
Beispiel #6
0
nsresult
SdpHelper::ParseMsid(const std::string& msidAttribute,
                     std::string* streamId,
                     std::string* trackId)
{
  // Would be nice if SdpSsrcAttributeList could parse out the contained
  // attribute, but at least the parse here is simple.
  // We are being very forgiving here wrt whitespace; tabs are not actually
  // allowed, nor is leading/trailing whitespace.
  size_t streamIdStart = msidAttribute.find_first_not_of(" \t", 5);
  // We do not assume the appdata token is here, since this is not
  // necessarily a webrtc msid
  if (streamIdStart == std::string::npos) {
    SDP_SET_ERROR("Malformed source-level msid attribute: "
        << msidAttribute);
    return NS_ERROR_INVALID_ARG;
  }

  size_t streamIdEnd = msidAttribute.find_first_of(" \t", streamIdStart);
  if (streamIdEnd == std::string::npos) {
    streamIdEnd = msidAttribute.size();
  }

  size_t trackIdStart =
    msidAttribute.find_first_not_of(" \t", streamIdEnd);
  if (trackIdStart == std::string::npos) {
    trackIdStart = msidAttribute.size();
  }

  size_t trackIdEnd = msidAttribute.find_first_of(" \t", trackIdStart);
  if (trackIdEnd == std::string::npos) {
    trackIdEnd = msidAttribute.size();
  }

  size_t streamIdSize = streamIdEnd - streamIdStart;
  size_t trackIdSize = trackIdEnd - trackIdStart;

  *streamId = msidAttribute.substr(streamIdStart, streamIdSize);
  *trackId = msidAttribute.substr(trackIdStart, trackIdSize);
  return NS_OK;
}
Beispiel #7
0
nsresult
SdpHelper::AddCandidateToSdp(Sdp* sdp,
                             const std::string& candidateUntrimmed,
                             const std::string& mid,
                             uint16_t level)
{

  if (level >= sdp->GetMediaSectionCount()) {
    SDP_SET_ERROR("Index " << level << " out of range");
    return NS_ERROR_INVALID_ARG;
  }

  // Trim off '[a=]candidate:'
  size_t begin = candidateUntrimmed.find(':');
  if (begin == std::string::npos) {
    SDP_SET_ERROR("Invalid candidate, no ':' (" << candidateUntrimmed << ")");
    return NS_ERROR_INVALID_ARG;
  }
  ++begin;

  std::string candidate = candidateUntrimmed.substr(begin);

  // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-11#section-3.4.2.1
  // Implementations receiving an ICE Candidate object MUST use the MID if
  // present, or the m= line index, if not (as it could have come from a
  // non-JSEP endpoint). (bug 1095793)
  SdpMediaSection* msection = 0;
  if (!mid.empty()) {
    // FindMsectionByMid could return nullptr
    msection = FindMsectionByMid(*sdp, mid);

    // Check to make sure mid matches what we'd get by
    // looking up the m= line using the level. (mjf)
    std::string checkMid;
    nsresult rv = GetMidFromLevel(*sdp, level, &checkMid);
    if (NS_FAILED(rv)) {
      return rv;
    }
    if (mid != checkMid) {
      SDP_SET_ERROR("Mismatch between mid and level - \"" << mid
                     << "\" is not the mid for level " << level
                     << "; \"" << checkMid << "\" is");
      return NS_ERROR_INVALID_ARG;
    }
  }
  if (!msection) {
    msection = &(sdp->GetMediaSection(level));
  }

  SdpAttributeList& attrList = msection->GetAttributeList();

  UniquePtr<SdpMultiStringAttribute> candidates;
  if (!attrList.HasAttribute(SdpAttribute::kCandidateAttribute)) {
    // Create new
    candidates.reset(
        new SdpMultiStringAttribute(SdpAttribute::kCandidateAttribute));
  } else {
    // Copy existing
    candidates.reset(new SdpMultiStringAttribute(
        *static_cast<const SdpMultiStringAttribute*>(
            attrList.GetAttribute(SdpAttribute::kCandidateAttribute))));
  }
  candidates->PushEntry(candidate);
  attrList.SetAttribute(candidates.release());

  return NS_OK;
}