Introduce webrtc::SdpType, the chosen enum for offer/pranswer/answer

This change introduces a new method |GetType()| in
SessionDescriptionInterface which returns an enum for the SDP type
rather than a string. Additionally, new overloads were added for
CreateSessionDescription to take SdpType instead of a type string.

Bug: webrtc:8613
Change-Id: I52b342f12155daf8d623646b0c21b7562f69d101
Reviewed-on: https://webrtc-review.googlesource.com/29380
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Reviewed-by: Zhi Huang <zhihuang@webrtc.org>
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21100}
This commit is contained in:
Steve Anton 2017-12-05 12:47:32 -08:00 committed by Commit Bot
parent 3fa0b98522
commit 88f2cb9479
5 changed files with 154 additions and 56 deletions

View File

@ -22,9 +22,11 @@
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
#include "api/optional.h"
#include "rtc_base/refcount.h"
namespace cricket {
@ -55,7 +57,7 @@ class IceCandidateInterface {
// m= section in SDP, which identifies the m= section.
virtual std::string sdp_mid() const = 0;
// This indicates the index (starting at zero) of m= section this candidate
// is assocated with. Needed when an endpoint doesn't support MIDs.
// is associated with. Needed when an endpoint doesn't support MIDs.
virtual int sdp_mline_index() const = 0;
// Only for use internally.
virtual const cricket::Candidate& candidate() const = 0;
@ -86,6 +88,26 @@ class IceCandidateCollection {
virtual const IceCandidateInterface* at(size_t index) const = 0;
};
// Enum that describes the type of the SessionDescriptionInterface.
// Corresponds to RTCSdpType in the WebRTC specification.
// https://w3c.github.io/webrtc-pc/#dom-rtcsdptype
enum class SdpType {
kOffer, // Description must be treated as an SDP offer.
kPrAnswer, // Description must be treated as an SDP answer, but not a final
// answer.
kAnswer // Description must be treated as an SDP final answer, and the offer-
// answer exchange must be considered complete after receiving this.
};
// Returns the string form of the given SDP type. String forms are defined in
// SessionDescriptionInterface.
const char* SdpTypeToString(SdpType type);
// Returns the SdpType from its string form. The string form can be one of the
// constants defined in SessionDescriptionInterface. Passing in any other string
// results in nullopt.
rtc::Optional<SdpType> SdpTypeFromString(const std::string& type_str);
// Class representation of an SDP session description.
//
// An instance of this interface is supposed to be owned by one class at a time
@ -94,7 +116,7 @@ class IceCandidateCollection {
// An instance can be created by CreateSessionDescription.
class SessionDescriptionInterface {
public:
// Supported types:
// String representations of the supported SDP types.
static const char kOffer[];
static const char kPrAnswer[];
static const char kAnswer[];
@ -110,7 +132,14 @@ class SessionDescriptionInterface {
virtual std::string session_id() const = 0;
virtual std::string session_version() const = 0;
// Returns the type of this session description as an SdpType. Descriptions of
// the various types are found in the SdpType documentation.
// TODO(steveanton): Remove default implementation once Chromium has been
// updated.
virtual SdpType GetType() const;
// kOffer/kPrAnswer/kAnswer
// TODO(steveanton): Remove this in favor of |GetType| that returns SdpType.
virtual std::string type() const = 0;
// Adds the specified candidate to the description.
@ -143,10 +172,24 @@ class SessionDescriptionInterface {
// Creates a SessionDescriptionInterface based on the SDP string and the type.
// Returns null if the sdp string can't be parsed or the type is unsupported.
// |error| may be null.
// TODO(steveanton): This function is deprecated. Please use the functions below
// which take an SdpType enum instead. Remove this once it is no longer used.
SessionDescriptionInterface* CreateSessionDescription(const std::string& type,
const std::string& sdp,
SdpParseError* error);
// Creates a SessionDescriptionInterface based on the SDP string and the type.
// Returns null if the SDP string cannot be parsed.
// If using the signature with |error_out|, details of the parsing error may be
// written to |error_out| if it is not null.
std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription(
SdpType type,
const std::string& sdp);
std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription(
SdpType type,
const std::string& sdp,
SdpParseError* error_out);
// CreateOffer and CreateAnswer callback interface.
class CreateSessionDescriptionObserver : public rtc::RefCountInterface {
public:

View File

@ -32,6 +32,8 @@ namespace webrtc {
// Implementation of SessionDescriptionInterface.
class JsepSessionDescription : public SessionDescriptionInterface {
public:
explicit JsepSessionDescription(SdpType type);
// TODO(steveanton): Remove this once callers have switched to SdpType.
explicit JsepSessionDescription(const std::string& type);
virtual ~JsepSessionDescription();
@ -54,11 +56,9 @@ class JsepSessionDescription : public SessionDescriptionInterface {
virtual std::string session_version() const {
return session_version_;
}
virtual std::string type() const {
return type_;
}
virtual SdpType GetType() const { return type_; }
virtual std::string type() const { return SdpTypeToString(type_); }
// Allows changing the type. Used for testing.
void set_type(const std::string& type) { type_ = type; }
virtual bool AddCandidate(const IceCandidateInterface* candidate);
virtual size_t RemoveCandidates(
const std::vector<cricket::Candidate>& candidates);
@ -74,7 +74,7 @@ class JsepSessionDescription : public SessionDescriptionInterface {
std::unique_ptr<cricket::SessionDescription> description_;
std::string session_id_;
std::string session_version_;
std::string type_;
SdpType type_;
std::vector<JsepCandidateCollection> candidate_collection_;
bool GetMediasectionIndex(const IceCandidateInterface* candidate,

View File

@ -12,46 +12,31 @@
#include <memory>
#include "p2p/base/port.h"
#include "pc/mediasession.h"
#include "pc/webrtcsdp.h"
#include "p2p/base/port.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/stringencode.h"
using cricket::SessionDescription;
namespace webrtc {
static const char* kSupportedTypes[] = {
JsepSessionDescription::kOffer,
JsepSessionDescription::kPrAnswer,
JsepSessionDescription::kAnswer
};
static bool IsTypeSupported(const std::string& type) {
bool type_supported = false;
for (size_t i = 0; i < arraysize(kSupportedTypes); ++i) {
if (kSupportedTypes[i] == type) {
type_supported = true;
break;
}
}
return type_supported;
}
namespace {
// RFC 5245
// It is RECOMMENDED that default candidates be chosen based on the
// likelihood of those candidates to work with the peer that is being
// contacted. It is RECOMMENDED that relayed > reflexive > host.
static const int kPreferenceUnknown = 0;
static const int kPreferenceHost = 1;
static const int kPreferenceReflexive = 2;
static const int kPreferenceRelayed = 3;
constexpr int kPreferenceUnknown = 0;
constexpr int kPreferenceHost = 1;
constexpr int kPreferenceReflexive = 2;
constexpr int kPreferenceRelayed = 3;
static const char kDummyAddress[] = "0.0.0.0";
static const int kDummyPort = 9;
constexpr char kDummyAddress[] = "0.0.0.0";
constexpr int kDummyPort = 9;
static int GetCandidatePreferenceFromType(const std::string& type) {
int GetCandidatePreferenceFromType(const std::string& type) {
int preference = kPreferenceUnknown;
if (type == cricket::LOCAL_PORT_TYPE) {
preference = kPreferenceHost;
@ -67,7 +52,7 @@ static int GetCandidatePreferenceFromType(const std::string& type) {
// Update the connection address for the MediaContentDescription based on the
// candidates.
static void UpdateConnectionAddress(
void UpdateConnectionAddress(
const JsepCandidateCollection& candidate_collection,
cricket::ContentDescription* content_description) {
int port = kDummyPort;
@ -107,6 +92,8 @@ static void UpdateConnectionAddress(
->set_connection_address(connection_addr);
}
} // namespace
const char SessionDescriptionInterface::kOffer[] = "offer";
const char SessionDescriptionInterface::kPrAnswer[] = "pranswer";
const char SessionDescriptionInterface::kAnswer[] = "answer";
@ -114,23 +101,85 @@ const char SessionDescriptionInterface::kAnswer[] = "answer";
const int JsepSessionDescription::kDefaultVideoCodecId = 100;
const char JsepSessionDescription::kDefaultVideoCodecName[] = "VP8";
const char* SdpTypeToString(SdpType type) {
switch (type) {
case SdpType::kOffer:
return SessionDescriptionInterface::kOffer;
case SdpType::kPrAnswer:
return SessionDescriptionInterface::kPrAnswer;
case SdpType::kAnswer:
return SessionDescriptionInterface::kAnswer;
}
return "";
}
rtc::Optional<SdpType> SdpTypeFromString(const std::string& type_str) {
if (type_str == SessionDescriptionInterface::kOffer) {
return SdpType::kOffer;
} else if (type_str == SessionDescriptionInterface::kPrAnswer) {
return SdpType::kPrAnswer;
} else if (type_str == SessionDescriptionInterface::kAnswer) {
return SdpType::kAnswer;
} else {
return rtc::nullopt;
}
}
// TODO(steveanton): Remove this default implementation once Chromium has been
// updated.
SdpType SessionDescriptionInterface::GetType() const {
rtc::Optional<SdpType> maybe_type = SdpTypeFromString(type());
if (maybe_type) {
return *maybe_type;
} else {
RTC_LOG(LS_WARNING) << "Default implementation of "
"SessionDescriptionInterface::GetType does not "
"recognize the result from type(), returning "
"kOffer.";
return SdpType::kOffer;
}
}
SessionDescriptionInterface* CreateSessionDescription(const std::string& type,
const std::string& sdp,
SdpParseError* error) {
if (!IsTypeSupported(type)) {
return NULL;
rtc::Optional<SdpType> maybe_type = SdpTypeFromString(type);
if (!maybe_type) {
return nullptr;
}
JsepSessionDescription* jsep_desc = new JsepSessionDescription(type);
if (!SdpDeserialize(sdp, jsep_desc, error)) {
delete jsep_desc;
return NULL;
}
return jsep_desc;
return CreateSessionDescription(*maybe_type, sdp, error).release();
}
JsepSessionDescription::JsepSessionDescription(const std::string& type)
: type_(type) {
std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription(
SdpType type,
const std::string& sdp) {
return CreateSessionDescription(type, sdp, nullptr);
}
std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription(
SdpType type,
const std::string& sdp,
SdpParseError* error_out) {
auto jsep_desc = rtc::MakeUnique<JsepSessionDescription>(type);
if (!SdpDeserialize(sdp, jsep_desc.get(), error_out)) {
return nullptr;
}
return std::move(jsep_desc);
}
JsepSessionDescription::JsepSessionDescription(SdpType type) : type_(type) {}
JsepSessionDescription::JsepSessionDescription(const std::string& type) {
rtc::Optional<SdpType> maybe_type = SdpTypeFromString(type);
if (maybe_type) {
type_ = *maybe_type;
} else {
RTC_LOG(LS_WARNING)
<< "JsepSessionDescription constructed with invalid type string: "
<< type << ". Assuming it is an offer.";
type_ = SdpType::kOffer;
}
}
JsepSessionDescription::~JsepSessionDescription() {}

View File

@ -22,10 +22,12 @@
#include "rtc_base/gunit.h"
#include "rtc_base/stringencode.h"
using ::testing::Values;
using webrtc::IceCandidateCollection;
using webrtc::IceCandidateInterface;
using webrtc::JsepIceCandidate;
using webrtc::JsepSessionDescription;
using webrtc::SdpType;
using webrtc::SessionDescriptionInterface;
static const char kCandidateUfrag[] = "ufrag";
@ -405,3 +407,20 @@ TEST_F(JsepSessionDescriptionTest, RemoveCandidateAndSetConnectionAddress) {
ASSERT_TRUE(jsep_desc_->RemoveCandidates(candidates));
EXPECT_EQ("0.0.0.0:9", media_desc->connection_address().ToString());
}
class EnumerateAllSdpTypesTest : public ::testing::Test,
public ::testing::WithParamInterface<SdpType> {
};
TEST_P(EnumerateAllSdpTypesTest, TestIdentity) {
SdpType type = GetParam();
const char* str = webrtc::SdpTypeToString(type);
EXPECT_EQ(type, webrtc::SdpTypeFromString(str));
}
INSTANTIATE_TEST_CASE_P(JsepSessionDescriptionTest,
EnumerateAllSdpTypesTest,
Values(SdpType::kOffer,
SdpType::kPrAnswer,
SdpType::kAnswer));

View File

@ -513,19 +513,6 @@ TEST_F(PeerConnectionCryptoUnitTest,
// CreateOffer/CreateAnswer calls are made while waiting for the certificate,
// they all finish after the certificate is generated.
// Whether the test will call CreateOffer or CreateAnswer.
enum class SdpType { kOffer, kAnswer };
std::ostream& operator<<(std::ostream& out, SdpType value) {
switch (value) {
case SdpType::kOffer:
return out << "offer";
case SdpType::kAnswer:
return out << "answer";
default:
return out << "unknown";
}
}
// Whether the certificate will be generated before calling CreateOffer or
// while CreateOffer is executing.
enum class CertGenTime { kBefore, kDuring };