Files
platform-external-webrtc/webrtc/api/rtcerror.h
deadbeef e814a0dee0 Adding "adapter" ORTC objects on top of ChannelManager/BaseChannel/etc.
This CL adds the following interfaces:
* RtpTransportController
* RtpTransport
* RtpSender
* RtpReceiver

They're implemented on top of the "BaseChannel" object, which is normally used
in a PeerConnection, and roughly corresponds to an SDP "m=" section. As a result
of this, there are several limitations:

* You can only have one of each type of sender and receiver (audio/video) on top
  of the same transport controller.
* The sender/receiver with the same media type must use the same RTP transport.
* You can't change the transport after creating the sender or receiver.
* Some of the parameters aren't supported.

Later, these "adapter" objects will be gradually replaced by real objects that don't
have these limitations, as "BaseChannel", "MediaChannel" and related code is
restructured. In this CL, we essentially have:

ORTC adapter objects -> BaseChannel -> Media engine
PeerConnection -> BaseChannel -> Media engine

And later we hope to have simply:

PeerConnection -> "Real" ORTC objects -> Media engine

See the linked bug for more context.

BUG=webrtc:7013
TBR=stefan@webrtc.org

Review-Url: https://codereview.webrtc.org/2675173003
Cr-Commit-Position: refs/heads/master@{#16842}
2017-02-26 02:15:09 +00:00

301 lines
11 KiB
C++

/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_API_RTCERROR_H_
#define WEBRTC_API_RTCERROR_H_
#include <ostream>
#include <string>
#include <utility> // For std::move.
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
namespace webrtc {
// Enumeration to represent distinct classes of errors that an application
// may wish to act upon differently. These roughly map to DOMExceptions or
// RTCError "errorDetailEnum" values in the web API, as described in the
// comments below.
enum class RTCErrorType {
// No error.
NONE,
// An operation is valid, but currently unsupported.
// Maps to OperationError DOMException.
UNSUPPORTED_OPERATION,
// A supplied parameter is valid, but currently unsupported.
// Maps to OperationError DOMException.
UNSUPPORTED_PARAMETER,
// General error indicating that a supplied parameter is invalid.
// Maps to InvalidAccessError or TypeError DOMException depending on context.
INVALID_PARAMETER,
// Slightly more specific than INVALID_PARAMETER; a parameter's value was
// outside the allowed range.
// Maps to RangeError DOMException.
INVALID_RANGE,
// Slightly more specific than INVALID_PARAMETER; an error occurred while
// parsing string input.
// Maps to SyntaxError DOMException.
SYNTAX_ERROR,
// The object does not support this operation in its current state.
// Maps to InvalidStateError DOMException.
INVALID_STATE,
// An attempt was made to modify the object in an invalid way.
// Maps to InvalidModificationError DOMException.
INVALID_MODIFICATION,
// An error occurred within an underlying network protocol.
// Maps to NetworkError DOMException.
NETWORK_ERROR,
// Some resource has been exhausted; file handles, hardware resources, ports,
// etc.
// Maps to OperationError DOMException.
RESOURCE_EXHAUSTED,
// The operation failed due to an internal error.
// Maps to OperationError DOMException.
INTERNAL_ERROR,
};
// Roughly corresponds to RTCError in the web api. Holds an error type, a
// message, and possibly additional information specific to that error.
//
// Doesn't contain anything beyond a type and message now, but will in the
// future as more errors are implemented.
class RTCError {
public:
// Constructors.
// Creates a "no error" error.
RTCError() {}
explicit RTCError(RTCErrorType type) : type_(type) {}
// For performance, prefer using the constructor that takes a const char* if
// the message is a static string.
RTCError(RTCErrorType type, const char* message)
: type_(type), static_message_(message), have_string_message_(false) {}
RTCError(RTCErrorType type, std::string&& message)
: type_(type), string_message_(message), have_string_message_(true) {}
// Delete the copy constructor and assignment operator; there aren't any use
// cases where you should need to copy an RTCError, as opposed to moving it.
// Can revisit this decision if use cases arise in the future.
RTCError(const RTCError& other) = delete;
RTCError& operator=(const RTCError& other) = delete;
// Move constructor and move-assignment operator.
RTCError(RTCError&& other);
RTCError& operator=(RTCError&& other);
~RTCError();
// Identical to default constructed error.
//
// Preferred over the default constructor for code readability.
static RTCError OK();
// Error type.
RTCErrorType type() const { return type_; }
void set_type(RTCErrorType type) { type_ = type; }
// Human-readable message describing the error. Shouldn't be used for
// anything but logging/diagnostics, since messages are not guaranteed to be
// stable.
const char* message() const;
// For performance, prefer using the method that takes a const char* if the
// message is a static string.
void set_message(const char* message);
void set_message(std::string&& message);
// Convenience method for situations where you only care whether or not an
// error occurred.
bool ok() const { return type_ == RTCErrorType::NONE; }
private:
RTCErrorType type_ = RTCErrorType::NONE;
// For performance, we use static strings wherever possible. But in some
// cases the error string may need to be constructed, in which case an
// std::string is used.
union {
const char* static_message_ = "";
std::string string_message_;
};
// Whether or not |static_message_| or |string_message_| is being used in the
// above union.
bool have_string_message_ = false;
};
// Outputs the error as a friendly string. Update this method when adding a new
// error type.
//
// Only intended to be used for logging/disagnostics.
std::ostream& operator<<(std::ostream& stream, RTCErrorType error);
// Helper macro that can be used by implementations to create an error with a
// message and log it. |message| should be a string literal or movable
// std::string.
#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \
{ \
RTC_DCHECK(type != RTCErrorType::NONE); \
LOG(severity) << message << " (" << type << ")"; \
return webrtc::RTCError(type, message); \
}
#define LOG_AND_RETURN_ERROR(type, message) \
LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR)
// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr
// models the concept of an object that is either a usable value, or an error
// Status explaining why such a value is not present. To this end RTCErrorOr<T>
// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is
// enforced by a debug check in most cases.
//
// The primary use-case for RTCErrorOr<T> is as the return value of a function
// which may fail. For example, CreateRtpSender will fail if the parameters
// could not be successfully applied at the media engine level, but if
// successful will return a unique_ptr to an RtpSender.
//
// Example client usage for a RTCErrorOr<std::unique_ptr<T>>:
//
// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
// if (result.ok()) {
// std::unique_ptr<Foo> foo = result.ConsumeValue();
// foo->DoSomethingCool();
// } else {
// LOG(LS_ERROR) << result.error();
// }
//
// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>:
//
// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) {
// if (arg <= 0) {
// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive");
// } else {
// return std::unique_ptr<Foo>(new Foo(arg));
// }
// }
//
template <typename T>
class RTCErrorOr {
// Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit
// conversion from Foo to Bar exists.
template <typename U>
friend class RTCErrorOr;
public:
typedef T element_type;
// Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This
// is marked 'explicit' to try to catch cases like 'return {};', where people
// think RTCErrorOr<std::vector<int>> will be initialized with an empty
// vector, instead of a RTCErrorType::INTERNAL_ERROR error.
explicit RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {}
// Constructs a new RTCErrorOr with the given non-ok error. After calling
// this constructor, calls to value() will DCHECK-fail.
//
// NOTE: Not explicit - we want to use RTCErrorOr<T> as a return
// value, so it is convenient and sensible to be able to do 'return
// RTCError(...)' when the return type is RTCErrorOr<T>.
//
// REQUIRES: !error.ok(). This requirement is DCHECKed.
RTCErrorOr(RTCError&& error) : error_(std::move(error)) {
RTC_DCHECK(!error.ok());
}
// Constructs a new RTCErrorOr with the given value. After calling this
// constructor, calls to value() will succeed, and calls to error() will
// return a default-constructed RTCError.
//
// NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type
// so it is convenient and sensible to be able to do 'return T()'
// when the return type is RTCErrorOr<T>.
RTCErrorOr(T&& value) : value_(std::move(value)) {}
// Delete the copy constructor and assignment operator; there aren't any use
// cases where you should need to copy an RTCErrorOr, as opposed to moving
// it. Can revisit this decision if use cases arise in the future.
RTCErrorOr(const RTCErrorOr& other) = delete;
RTCErrorOr& operator=(const RTCErrorOr& other) = delete;
// Move constructor and move-assignment operator.
//
// Visual Studio doesn't support "= default" with move constructors or
// assignment operators (even though they compile, they segfault), so define
// them explicitly.
RTCErrorOr(RTCErrorOr&& other)
: error_(std::move(other.error_)), value_(std::move(other.value_)) {}
RTCErrorOr& operator=(RTCErrorOr&& other) {
error_ = std::move(other.error_);
value_ = std::move(other.value_);
return *this;
}
// Conversion constructor and assignment operator; T must be copy or move
// constructible from U.
template <typename U>
RTCErrorOr(RTCErrorOr<U> other)
: error_(std::move(other.error_)), value_(std::move(other.value_)) {}
template <typename U>
RTCErrorOr& operator=(RTCErrorOr<U> other) {
error_ = std::move(other.error_);
value_ = std::move(other.value_);
return *this;
}
// Returns a reference to our error. If this contains a T, then returns
// default-constructed RTCError.
const RTCError& error() const { return error_; }
// Moves the error. Can be useful if, say "CreateFoo" returns an
// RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an
// RTCErrorOr<Bar>, and wants to forward the error up the stack.
RTCError MoveError() { return std::move(error_); }
// Returns this->error().ok()
bool ok() const { return error_.ok(); }
// Returns a reference to our current value, or DCHECK-fails if !this->ok().
//
// Can be convenient for the implementation; for example, a method may want
// to access the value in some way before returning it to the next method on
// the stack.
const T& value() const {
RTC_DCHECK(ok());
return value_;
}
T& value() {
RTC_DCHECK(ok());
return value_;
}
// Moves our current value out of this object and returns it, or DCHECK-fails
// if !this->ok().
T MoveValue() {
RTC_DCHECK(ok());
return std::move(value_);
}
private:
RTCError error_;
T value_;
};
} // namespace webrtc
#endif // WEBRTC_API_RTCERROR_H_