jsep.h (16321B)
1 /* 2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 // This file contains declarations of interfaces that wrap SDP-related 12 // constructs; session descriptions and ICE candidates. The inner "webrtc::" 13 // objects shouldn't be accessed directly; the intention is that an application 14 // using the PeerConnection API only creates these objects from strings, and 15 // them passes them into the PeerConnection. 16 // 17 // Though in the future, we're planning to provide an SDP parsing API, with a 18 // structure more friendly than webrtc::SessionDescription. 19 20 #ifndef API_JSEP_H_ 21 #define API_JSEP_H_ 22 23 #include <stddef.h> 24 25 #include <memory> 26 #include <optional> 27 #include <string> 28 #include <utility> 29 #include <vector> 30 31 #include "absl/base/nullability.h" 32 #include "absl/strings/str_format.h" 33 #include "absl/strings/string_view.h" 34 #include "api/candidate.h" 35 #include "api/ref_count.h" 36 #include "api/rtc_error.h" 37 #include "api/sequence_checker.h" 38 #include "rtc_base/system/no_unique_address.h" 39 #include "rtc_base/system/rtc_export.h" 40 41 namespace webrtc { 42 43 class SessionDescription; 44 45 struct SdpParseError { 46 public: 47 // The sdp line that causes the error. 48 std::string line; 49 // Explains the error. 50 std::string description; 51 }; 52 53 // Class representation of an ICE candidate. 54 class RTC_EXPORT IceCandidate final { 55 public: 56 IceCandidate(absl::string_view sdp_mid, 57 int sdp_mline_index, 58 const Candidate& candidate); 59 ~IceCandidate() = default; 60 61 IceCandidate(const IceCandidate&) = delete; 62 IceCandidate& operator=(const IceCandidate&) = delete; 63 64 // Parses an sdp candidate string (only the first line) to construct an 65 // IceCandidate instance. If an error occurs, details about the error can 66 // optionally be returned via the `error` paramter, and the function returns 67 // nullptr. 68 static std::unique_ptr<IceCandidate> Create( 69 absl::string_view mid, 70 int sdp_mline_index, 71 absl::string_view sdp, 72 SdpParseError* absl_nullable error = nullptr); 73 74 // If present, this is the value of the "a=mid" attribute of the candidate's 75 // m= section in SDP, which identifies the m= section. 76 // TODO: webrtc:406795492 - string_view. 77 std::string sdp_mid() const { return sdp_mid_; } 78 79 // This indicates the index (starting at zero) of m= section this candidate 80 // is associated with. Needed when an endpoint doesn't support MIDs. 81 int sdp_mline_index() const { return sdp_mline_index_; } 82 83 // Only for use internally. 84 const Candidate& candidate() const { return candidate_; } 85 86 // The URL of the ICE server which this candidate was gathered from. 87 // TODO: webrtc:406795492 - string_view. 88 std::string server_url() const { return candidate_.url(); } 89 90 // Creates a SDP-ized form of this candidate. 91 std::string ToString() const; 92 93 // TODO: webrtc:406795492 - Deprecate and remove this method. 94 bool ToString(std::string* out) const { 95 if (!out) 96 return false; 97 *out = ToString(); 98 return !out->empty(); 99 } 100 101 template <typename Sink> 102 friend void AbslStringify(Sink& sink, const IceCandidate& c) { 103 absl::Format(&sink, "IceCandidate: {'%s', %i, '%s'}", c.sdp_mid_.c_str(), 104 c.sdp_mline_index_, c.ToString().c_str()); 105 } 106 107 private: 108 const std::string sdp_mid_; 109 const int sdp_mline_index_; 110 const Candidate candidate_; 111 }; 112 113 // TODO: webrtc:406795492 - Deprecate and eventually remove these types when no 114 // longer referenced. They're provided here for backwards compatiblity. 115 using JsepIceCandidate = IceCandidate; 116 using IceCandidateInterface = IceCandidate; 117 118 // Creates an IceCandidate based on SDP string. 119 // Returns null if the sdp string can't be parsed. 120 // `error` may be null. 121 RTC_EXPORT IceCandidate* CreateIceCandidate(const std::string& sdp_mid, 122 int sdp_mline_index, 123 const std::string& sdp, 124 SdpParseError* error); 125 126 // Creates an IceCandidate based on a parsed candidate structure. 127 RTC_EXPORT std::unique_ptr<IceCandidate> CreateIceCandidate( 128 const std::string& sdp_mid, 129 int sdp_mline_index, 130 const Candidate& candidate); 131 132 // This class represents a collection of candidates for a specific m= section. 133 // Used in SessionDescriptionInterface. 134 class IceCandidateCollection final { 135 public: 136 IceCandidateCollection() = default; 137 explicit IceCandidateCollection( 138 std::vector<std::unique_ptr<IceCandidate>>&& candidates) 139 : candidates_(std::move(candidates)) {} 140 ~IceCandidateCollection() = default; 141 142 // Move constructor is defined so that a vector of IceCandidateCollections 143 // can be resized. 144 IceCandidateCollection(IceCandidateCollection&& o) = default; 145 146 IceCandidateCollection(const IceCandidateCollection&) = delete; 147 IceCandidateCollection& operator=(const IceCandidateCollection&) = delete; 148 149 size_t count() const { return candidates_.size(); } 150 bool empty() const { return candidates_.empty(); } 151 const IceCandidate* at(size_t index) const; 152 153 // Adds and takes ownership of the IceCandidate. 154 void add(std::unique_ptr<IceCandidate> candidate); 155 [[deprecated("Use unique_ptr version")]] 156 void add(IceCandidate* candidate); 157 158 // Appends a collection of candidates. 159 void Append(IceCandidateCollection collection); 160 161 // Removes the candidate that has a matching address and protocol. 162 // 163 // Returns the number of candidates that were removed. 164 size_t remove(const IceCandidate* candidate); 165 166 const std::vector<std::unique_ptr<IceCandidate>>& candidates() const { 167 return candidates_; 168 } 169 170 // Returns true if an equivalent `candidate` exist in the collection. 171 bool HasCandidate(const IceCandidate* candidate) const; 172 173 IceCandidateCollection Clone() const; 174 175 private: 176 std::vector<std::unique_ptr<IceCandidate>> candidates_; 177 }; 178 179 // TODO: webrtc:406795492 - Deprecate. 180 using JsepCandidateCollection = IceCandidateCollection; 181 182 // Enum that describes the type of the SessionDescriptionInterface. 183 // Corresponds to RTCSdpType in the WebRTC specification. 184 // https://w3c.github.io/webrtc-pc/#dom-rtcsdptype 185 enum class SdpType { 186 kOffer, // Description must be treated as an SDP offer. 187 kPrAnswer, // Description must be treated as an SDP answer, but not a final 188 // answer. 189 kAnswer, // Description must be treated as an SDP final answer, and the 190 // offer-answer exchange must be considered complete after 191 // receiving this. 192 kRollback // Resets any pending offers and sets signaling state back to 193 // stable. 194 }; 195 196 // Returns the string form of the given SDP type. String forms are defined in 197 // SessionDescriptionInterface. 198 RTC_EXPORT const char* SdpTypeToString(SdpType type); 199 200 template <typename Sink> 201 void AbslStringify(Sink& sink, SdpType sdp_type) { 202 sink.Append(SdpTypeToString(sdp_type)); 203 } 204 205 // Returns the SdpType from its string form. The string form can be one of the 206 // constants defined in SessionDescriptionInterface. Passing in any other string 207 // results in nullopt. 208 RTC_EXPORT std::optional<SdpType> SdpTypeFromString( 209 const std::string& type_str); 210 211 // TODO: bugs.webrtc.org/442220720 - This class is temporarily here while 212 // SessionDescriptionInterface transforms from a pure interface into a simple 213 // non-virtual class. The purpose of `SessionDescriptionInternal` is to provide 214 // protected methods to classes currently inheriting from 215 // SessionDescriptionInterface, the basic implementation that satisified the 216 // interface. Once the migration of the implementation is complete, the 217 // SessionDescriptionInterface class can be made non-virtual, final and 218 // SessionDescriptionInternal can effectively be renamed to 219 // SessionDescriptionInterface. The reason for all of this is that access to and 220 // modification of the internal state needs to be made thread aware so that 221 // concurrent operations aren't executed on different threads or that the 222 // state can be declared const when no known modifications are pending. 223 class SessionDescriptionInternal { 224 public: 225 explicit SessionDescriptionInternal( 226 SdpType type, 227 absl_nullable std::unique_ptr<SessionDescription> description, 228 absl::string_view id, 229 absl::string_view version); 230 231 ~SessionDescriptionInternal(); 232 233 // Resets the internal sequence_checker_ to not be attached to a particular 234 // thread. Used when transfering object ownership between threads. Must be 235 // called by the thread that currently owns the object before transferring the 236 // ownership. 237 void RelinquishThreadOwnership(); 238 239 protected: 240 // Only meant for the SessionDescriptionInterface implementation. 241 SdpType sdp_type() const { return sdp_type_; } 242 absl::string_view id() const { return id_; } 243 absl::string_view version() const { return version_; } 244 const SessionDescription* description() const { return description_.get(); } 245 SessionDescription* description() { return description_.get(); } 246 size_t mediasection_count() const; 247 248 protected: 249 // This method is necessarily `protected`, and not private, while 250 // the SessionDescriptionInterface implementation is being consolidated 251 // into a single class. 252 const SequenceChecker* sequence_checker() const { return &sequence_checker_; } 253 254 private: 255 RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_{ 256 SequenceChecker::kDetached}; 257 const SdpType sdp_type_; 258 const std::string id_; 259 const std::string version_; 260 absl_nullable const std::unique_ptr<SessionDescription> description_; 261 }; 262 263 // Class representation of an SDP session description. 264 // 265 // An instance of this interface is supposed to be owned by one class at a time 266 // and is therefore not expected to be thread safe. 267 // 268 // An instance can be created by CreateSessionDescription. 269 class RTC_EXPORT SessionDescriptionInterface 270 : public SessionDescriptionInternal { 271 public: 272 static std::unique_ptr<SessionDescriptionInterface> Create( 273 SdpType type, 274 std::unique_ptr<SessionDescription> description, 275 absl::string_view id, 276 absl::string_view version, 277 std::vector<IceCandidateCollection> candidates = {}); 278 279 SessionDescriptionInterface(const SessionDescriptionInterface&) = delete; 280 SessionDescriptionInterface& operator=(const SessionDescriptionInterface&) = 281 delete; 282 283 // String representations of the supported SDP types. 284 static const char kOffer[]; 285 static const char kPrAnswer[]; 286 static const char kAnswer[]; 287 static const char kRollback[]; 288 289 virtual ~SessionDescriptionInterface() {} 290 291 // Create a new SessionDescriptionInterface object 292 // with the same values as the old object. 293 virtual std::unique_ptr<SessionDescriptionInterface> Clone() const; 294 295 // Only for use internally. 296 virtual SessionDescription* description() { 297 return SessionDescriptionInternal::description(); 298 } 299 virtual const SessionDescription* description() const { 300 return SessionDescriptionInternal::description(); 301 } 302 303 // Get the session id and session version, which are defined based on 304 // RFC 4566 for the SDP o= line. 305 virtual std::string session_id() const { return std::string(id()); } 306 virtual std::string session_version() const { return std::string(version()); } 307 308 // Returns the type of this session description as an SdpType. Descriptions of 309 // the various types are found in the SdpType documentation. 310 virtual SdpType GetType() const { return sdp_type(); } 311 312 // TODO(steveanton): Remove this in favor of `GetType` that returns SdpType. 313 virtual std::string type() const { return SdpTypeToString(sdp_type()); } 314 315 // Adds the specified candidate to the description. 316 // 317 // Ownership is not transferred. 318 // 319 // Returns false if the session description does not have a media section 320 // that corresponds to `candidate.sdp_mid()` or 321 // `candidate.sdp_mline_index()`. 322 virtual bool AddCandidate(const IceCandidate* candidate); 323 324 // Removes the first matching candidate (at most 1) from the description 325 // that meets the `Candidate::MatchesForRemoval()` requirement and matches 326 // either the `IceCandidate::sdp_mid()` property or 327 // `IceCandidate::sdp_mline_index()`. 328 // 329 // Returns false if no matching candidate was found (and removed). 330 virtual bool RemoveCandidate(const IceCandidate* candidate); 331 332 // Returns the number of m= sections in the session description. 333 virtual size_t number_of_mediasections() const { 334 return mediasection_count(); 335 } 336 337 // Returns a collection of all candidates that belong to a certain m= 338 // section. 339 virtual const IceCandidateCollection* candidates( 340 size_t mediasection_index) const; 341 342 // Serializes the description to SDP. 343 virtual bool ToString(std::string* out) const; 344 345 template <typename Sink> 346 friend void AbslStringify(Sink& sink, const SessionDescriptionInterface& p) { 347 sink.Append("\n--- BEGIN SDP "); 348 absl::Format(&sink, "%v", p.GetType()); 349 sink.Append(" ---\n"); 350 std::string temp; 351 if (p.ToString(&temp)) { 352 sink.Append(temp); 353 } else { 354 sink.Append("Error in ToString\n"); 355 } 356 sink.Append("--- END SDP ---\n"); 357 } 358 359 protected: 360 explicit SessionDescriptionInterface( 361 SdpType type, 362 std::unique_ptr<SessionDescription> description, 363 absl::string_view id, 364 absl::string_view version, 365 std::vector<IceCandidateCollection> candidates = {}); 366 367 private: 368 bool IsValidMLineIndex(int index) const; 369 bool GetMediasectionIndex(const IceCandidate* candidate, size_t* index) const; 370 int GetMediasectionIndex(absl::string_view mid) const; 371 372 std::vector<IceCandidateCollection> candidate_collection_ 373 RTC_GUARDED_BY(sequence_checker()); 374 }; 375 376 // Creates a SessionDescriptionInterface based on the SDP string and the type. 377 // Returns null if the SDP string cannot be parsed. 378 // If using the signature with `error_out`, details of the parsing error may be 379 // written to `error_out` if it is not null. 380 RTC_EXPORT std::unique_ptr<SessionDescriptionInterface> 381 CreateSessionDescription(SdpType type, const std::string& sdp); 382 RTC_EXPORT std::unique_ptr<SessionDescriptionInterface> 383 CreateSessionDescription(SdpType type, 384 const std::string& sdp, 385 SdpParseError* error_out); 386 387 // Creates a SessionDescriptionInterface based on a parsed SDP structure and the 388 // given type, ID and version. 389 std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription( 390 SdpType type, 391 const std::string& session_id, 392 const std::string& session_version, 393 std::unique_ptr<SessionDescription> description); 394 395 // Creates a rollback session description object (SdpType::kRollback). 396 std::unique_ptr<SessionDescriptionInterface> CreateRollbackSessionDescription( 397 absl::string_view session_id = "", 398 absl::string_view session_version = ""); 399 400 // CreateOffer and CreateAnswer callback interface. 401 class RTC_EXPORT CreateSessionDescriptionObserver : public RefCountInterface { 402 public: 403 // This callback transfers the ownership of the `desc`. 404 // TODO(deadbeef): Make this take an std::unique_ptr<> to avoid confusion 405 // around ownership. 406 virtual void OnSuccess(SessionDescriptionInterface* desc) = 0; 407 // The OnFailure callback takes an RTCError, which consists of an 408 // error code and a string. 409 // RTCError is non-copyable, so it must be passed using std::move. 410 // Earlier versions of the API used a string argument. This version 411 // is removed; its functionality was the same as passing 412 // error.message. 413 virtual void OnFailure(RTCError error) = 0; 414 415 protected: 416 ~CreateSessionDescriptionObserver() override = default; 417 }; 418 419 // SetLocalDescription and SetRemoteDescription callback interface. 420 class RTC_EXPORT SetSessionDescriptionObserver : public RefCountInterface { 421 public: 422 virtual void OnSuccess() = 0; 423 // See description in CreateSessionDescriptionObserver for OnFailure. 424 virtual void OnFailure(RTCError error) = 0; 425 426 protected: 427 ~SetSessionDescriptionObserver() override = default; 428 }; 429 430 } // namespace webrtc 431 432 #endif // API_JSEP_H_