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}
diff --git a/api/jsep.h b/api/jsep.h
index acfffd4..c05f382 100644
--- a/api/jsep.h
+++ b/api/jsep.h
@@ -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 @@
// 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 @@
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 @@
// 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 @@
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 @@
// 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:
diff --git a/api/jsepsessiondescription.h b/api/jsepsessiondescription.h
index 6b115ee..70bb277 100644
--- a/api/jsepsessiondescription.h
+++ b/api/jsepsessiondescription.h
@@ -32,6 +32,8 @@
// 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 @@
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 @@
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,
diff --git a/pc/jsepsessiondescription.cc b/pc/jsepsessiondescription.cc
index e6b6d32..5e6a1cb 100644
--- a/pc/jsepsessiondescription.cc
+++ b/pc/jsepsessiondescription.cc
@@ -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 @@
// 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 @@
->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 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() {}
diff --git a/pc/jsepsessiondescription_unittest.cc b/pc/jsepsessiondescription_unittest.cc
index be24dcd..27b2cf1 100644
--- a/pc/jsepsessiondescription_unittest.cc
+++ b/pc/jsepsessiondescription_unittest.cc
@@ -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 @@
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));
diff --git a/pc/peerconnection_crypto_unittest.cc b/pc/peerconnection_crypto_unittest.cc
index 5d5296b..ab341f5 100644
--- a/pc/peerconnection_crypto_unittest.cc
+++ b/pc/peerconnection_crypto_unittest.cc
@@ -513,19 +513,6 @@
// 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 };