blob: fe08e3a909f8b815898dc8fa024594c9b31d3514 [file] [log] [blame]
* Copyright 2004 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.
#include <stddef.h>
#include <stdint.h>
#include <iosfwd>
#include <memory>
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "api/crypto_params.h"
#include "api/media_types.h"
#include "api/rtp_parameters.h"
#include "api/rtp_transceiver_interface.h"
#include "media/base/media_channel.h"
#include "media/base/stream_params.h"
#include "p2p/base/transport_description.h"
#include "p2p/base/transport_info.h"
#include "pc/media_protocol_names.h"
#include "pc/simulcast_description.h"
#include "rtc_base/deprecation.h"
#include "rtc_base/socket_address.h"
namespace cricket {
typedef std::vector<AudioCodec> AudioCodecs;
typedef std::vector<VideoCodec> VideoCodecs;
typedef std::vector<RtpDataCodec> RtpDataCodecs;
typedef std::vector<CryptoParams> CryptoParamsVec;
typedef std::vector<webrtc::RtpExtension> RtpHeaderExtensions;
extern const char kMediaProtocolAvpf[];
extern const char kMediaProtocolSavpf[];
extern const char kMediaProtocolDtlsSavpf[];
// Options to control how session descriptions are generated.
const int kAutoBandwidth = -1;
class AudioContentDescription;
class VideoContentDescription;
class DataContentDescription;
class RtpDataContentDescription;
class SctpDataContentDescription;
// Describes a session description media section. There are subclasses for each
// media type (audio, video, data) that will have additional information.
class MediaContentDescription {
MediaContentDescription() = default;
virtual ~MediaContentDescription() = default;
virtual MediaType type() const = 0;
// Try to cast this media description to an AudioContentDescription. Returns
// nullptr if the cast fails.
virtual AudioContentDescription* as_audio() { return nullptr; }
virtual const AudioContentDescription* as_audio() const { return nullptr; }
// Try to cast this media description to a VideoContentDescription. Returns
// nullptr if the cast fails.
virtual VideoContentDescription* as_video() { return nullptr; }
virtual const VideoContentDescription* as_video() const { return nullptr; }
// Backwards compatible shim: Return a shim object that allows
// callers to ignore the distinction between RtpDataContentDescription
// and SctpDataContentDescription objects.
virtual DataContentDescription* as_data() { return nullptr; }
virtual const DataContentDescription* as_data() const { return nullptr; }
virtual RtpDataContentDescription* as_rtp_data() { return nullptr; }
virtual const RtpDataContentDescription* as_rtp_data() const {
return nullptr;
virtual SctpDataContentDescription* as_sctp() { return nullptr; }
virtual const SctpDataContentDescription* as_sctp() const { return nullptr; }
virtual bool has_codecs() const = 0;
virtual MediaContentDescription* Copy() const = 0;
// |protocol| is the expected media transport protocol, such as RTP/AVPF,
virtual std::string protocol() const { return protocol_; }
virtual void set_protocol(const std::string& protocol) {
protocol_ = protocol;
virtual webrtc::RtpTransceiverDirection direction() const {
return direction_;
virtual void set_direction(webrtc::RtpTransceiverDirection direction) {
direction_ = direction;
virtual bool rtcp_mux() const { return rtcp_mux_; }
virtual void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
virtual bool rtcp_reduced_size() const { return rtcp_reduced_size_; }
virtual void set_rtcp_reduced_size(bool reduced_size) {
rtcp_reduced_size_ = reduced_size;
virtual int bandwidth() const { return bandwidth_; }
virtual void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
virtual const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
virtual void AddCrypto(const CryptoParams& params) {
virtual void set_cryptos(const std::vector<CryptoParams>& cryptos) {
cryptos_ = cryptos;
virtual const RtpHeaderExtensions& rtp_header_extensions() const {
return rtp_header_extensions_;
virtual void set_rtp_header_extensions(
const RtpHeaderExtensions& extensions) {
rtp_header_extensions_ = extensions;
rtp_header_extensions_set_ = true;
virtual void AddRtpHeaderExtension(const webrtc::RtpExtension& ext) {
rtp_header_extensions_set_ = true;
virtual void AddRtpHeaderExtension(const cricket::RtpHeaderExtension& ext) {
webrtc::RtpExtension webrtc_extension;
webrtc_extension.uri = ext.uri; =;
rtp_header_extensions_set_ = true;
virtual void ClearRtpHeaderExtensions() {
rtp_header_extensions_set_ = true;
// We can't always tell if an empty list of header extensions is
// because the other side doesn't support them, or just isn't hooked up to
// signal them. For now we assume an empty list means no signaling, but
// provide the ClearRtpHeaderExtensions method to allow "no support" to be
// clearly indicated (i.e. when derived from other information).
virtual bool rtp_header_extensions_set() const {
return rtp_header_extensions_set_;
virtual const StreamParamsVec& streams() const { return send_streams_; }
// TODO(pthatcher): Remove this by giving access
// to MediaContentDescription
virtual StreamParamsVec& mutable_streams() { return send_streams_; }
virtual void AddStream(const StreamParams& stream) {
// Legacy streams have an ssrc, but nothing else.
void AddLegacyStream(uint32_t ssrc) {
void AddLegacyStream(uint32_t ssrc, uint32_t fid_ssrc) {
StreamParams sp = StreamParams::CreateLegacy(ssrc);
sp.AddFidSsrc(ssrc, fid_ssrc);
// Sets the CNAME of all StreamParams if it have not been set.
virtual void SetCnameIfEmpty(const std::string& cname) {
for (cricket::StreamParamsVec::iterator it = send_streams_.begin();
it != send_streams_.end(); ++it) {
if (it->cname.empty())
it->cname = cname;
virtual uint32_t first_ssrc() const {
if (send_streams_.empty()) {
return 0;
return send_streams_[0].first_ssrc();
virtual bool has_ssrcs() const {
if (send_streams_.empty()) {
return false;
return send_streams_[0].has_ssrcs();
virtual void set_conference_mode(bool enable) { conference_mode_ = enable; }
virtual bool conference_mode() const { return conference_mode_; }
// May be present at the media or session level of SDP. If present at both
// levels, the media-level attribute overwrites the session-level one.
virtual void set_connection_address(const rtc::SocketAddress& address) {
connection_address_ = address;
virtual const rtc::SocketAddress& connection_address() const {
return connection_address_;
// Determines if it's allowed to mix one- and two-byte rtp header extensions
// within the same rtp stream.
enum ExtmapAllowMixed { kNo, kSession, kMedia };
virtual void set_extmap_allow_mixed_enum(
ExtmapAllowMixed new_extmap_allow_mixed) {
if (new_extmap_allow_mixed == kMedia &&
extmap_allow_mixed_enum_ == kSession) {
// Do not downgrade from session level to media level.
extmap_allow_mixed_enum_ = new_extmap_allow_mixed;
virtual ExtmapAllowMixed extmap_allow_mixed_enum() const {
return extmap_allow_mixed_enum_;
virtual bool extmap_allow_mixed() const {
return extmap_allow_mixed_enum_ != kNo;
// Simulcast functionality.
virtual bool HasSimulcast() const { return !simulcast_.empty(); }
virtual SimulcastDescription& simulcast_description() { return simulcast_; }
virtual const SimulcastDescription& simulcast_description() const {
return simulcast_;
virtual void set_simulcast_description(
const SimulcastDescription& simulcast) {
simulcast_ = simulcast;
bool rtcp_mux_ = false;
bool rtcp_reduced_size_ = false;
int bandwidth_ = kAutoBandwidth;
std::string protocol_;
std::vector<CryptoParams> cryptos_;
std::vector<webrtc::RtpExtension> rtp_header_extensions_;
bool rtp_header_extensions_set_ = false;
StreamParamsVec send_streams_;
bool conference_mode_ = false;
webrtc::RtpTransceiverDirection direction_ =
rtc::SocketAddress connection_address_;
// Mixed one- and two-byte header not included in offer on media level or
// session level, but we will respond that we support it. The plan is to add
// it to our offer on session level. See todo in SessionDescription.
ExtmapAllowMixed extmap_allow_mixed_enum_ = kNo;
SimulcastDescription simulcast_;
// TODO( Remove this alias once downstream projects have
// updated.
using ContentDescription = MediaContentDescription;
template <class C>
class MediaContentDescriptionImpl : public MediaContentDescription {
void set_protocol(const std::string& protocol) override {
protocol_ = protocol;
typedef C CodecType;
// Codecs should be in preference order (most preferred codec first).
virtual const std::vector<C>& codecs() const { return codecs_; }
virtual void set_codecs(const std::vector<C>& codecs) { codecs_ = codecs; }
bool has_codecs() const override { return !codecs_.empty(); }
virtual bool HasCodec(int id) {
bool found = false;
for (typename std::vector<C>::iterator iter = codecs_.begin();
iter != codecs_.end(); ++iter) {
if (iter->id == id) {
found = true;
return found;
virtual void AddCodec(const C& codec) { codecs_.push_back(codec); }
virtual void AddOrReplaceCodec(const C& codec) {
for (typename std::vector<C>::iterator iter = codecs_.begin();
iter != codecs_.end(); ++iter) {
if (iter->id == {
*iter = codec;
virtual void AddCodecs(const std::vector<C>& codecs) {
typename std::vector<C>::const_iterator codec;
for (codec = codecs.begin(); codec != codecs.end(); ++codec) {
std::vector<C> codecs_;
class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> {
AudioContentDescription() {}
virtual AudioContentDescription* Copy() const {
return new AudioContentDescription(*this);
virtual MediaType type() const { return MEDIA_TYPE_AUDIO; }
virtual AudioContentDescription* as_audio() { return this; }
virtual const AudioContentDescription* as_audio() const { return this; }
class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
virtual VideoContentDescription* Copy() const {
return new VideoContentDescription(*this);
virtual MediaType type() const { return MEDIA_TYPE_VIDEO; }
virtual VideoContentDescription* as_video() { return this; }
virtual const VideoContentDescription* as_video() const { return this; }
// The DataContentDescription is a shim over the RtpDataContentDescription
// and SctpDataContentDescription classes that is used for external callers
// into this internal API.
// It is a templated derivation of MediaContentDescriptionImpl because
// that's what the external caller expects it to be.
// TODO( Declare this class obsolete and remove it
// once external callers have been updated.
class DataContentDescription : public MediaContentDescriptionImpl<DataCodec> {
MediaType type() const override { return MEDIA_TYPE_DATA; }
DataContentDescription* as_data() override { return this; }
const DataContentDescription* as_data() const override { return this; }
// Override all methods defined in MediaContentDescription.
bool has_codecs() const override;
DataContentDescription* Copy() const override {
return new DataContentDescription(this);
std::string protocol() const override;
void set_protocol(const std::string& protocol) override;
webrtc::RtpTransceiverDirection direction() const override;
void set_direction(webrtc::RtpTransceiverDirection direction) override;
bool rtcp_mux() const override;
void set_rtcp_mux(bool mux) override;
bool rtcp_reduced_size() const override;
void set_rtcp_reduced_size(bool) override;
int bandwidth() const override;
void set_bandwidth(int bandwidth) override;
const std::vector<CryptoParams>& cryptos() const override;
void AddCrypto(const CryptoParams& params) override;
void set_cryptos(const std::vector<CryptoParams>& cryptos) override;
const RtpHeaderExtensions& rtp_header_extensions() const override;
void set_rtp_header_extensions(
const RtpHeaderExtensions& extensions) override;
void AddRtpHeaderExtension(const webrtc::RtpExtension& ext) override;
void AddRtpHeaderExtension(const cricket::RtpHeaderExtension& ext) override;
void ClearRtpHeaderExtensions() override;
bool rtp_header_extensions_set() const override;
const StreamParamsVec& streams() const override;
StreamParamsVec& mutable_streams() override;
void AddStream(const StreamParams& stream) override;
void SetCnameIfEmpty(const std::string& cname) override;
uint32_t first_ssrc() const override;
bool has_ssrcs() const override;
void set_conference_mode(bool enable) override;
bool conference_mode() const override;
void set_connection_address(const rtc::SocketAddress& address) override;
const rtc::SocketAddress& connection_address() const override;
void set_extmap_allow_mixed_enum(ExtmapAllowMixed) override;
ExtmapAllowMixed extmap_allow_mixed_enum() const override;
bool HasSimulcast() const override;
SimulcastDescription& simulcast_description() override;
const SimulcastDescription& simulcast_description() const override;
void set_simulcast_description(
const SimulcastDescription& simulcast) override;
// Override all methods defined in MediaContentDescriptionImpl.
const std::vector<CodecType>& codecs() const override;
void set_codecs(const std::vector<CodecType>& codecs) override;
bool HasCodec(int id) override;
void AddCodec(const CodecType& codec) override;
void AddOrReplaceCodec(const CodecType& codec) override;
void AddCodecs(const std::vector<CodecType>& codec) override;
typedef MediaContentDescriptionImpl<DataCodec> Super;
// Friend classes are allowed to create proxies for themselves.
friend class RtpDataContentDescription; // for constructors
friend class SctpDataContentDescription;
friend class SessionDescription; // for Unshim()
// Copy constructor. A copy results in an object that owns its
// real description, which is a copy of the original description
// (whether that was owned or not).
explicit DataContentDescription(const DataContentDescription* o);
explicit DataContentDescription(RtpDataContentDescription*);
explicit DataContentDescription(SctpDataContentDescription*);
// Exposed for internal use - new clients should not use this class.
RtpDataContentDescription* as_rtp_data() override;
SctpDataContentDescription* as_sctp() override;
// Create a shimmed object, owned by the shim.
void CreateShimTarget(bool is_sctp);
// Return the shimmed object, passing ownership if owned, and set
// |should_delete| to true if it was the owner. If |should_delete|
// is true on return, the caller should immediately delete the
// DataContentDescription object.
MediaContentDescription* Unshim(bool* should_delete);
// Returns whether SCTP is in use. False when it's not decided.
bool IsSctp() const;
// Check function for use when caller obviously assumes RTP.
void EnsureIsRtp();
MediaContentDescription* real_description_ = nullptr;
std::unique_ptr<MediaContentDescription> owned_description_;
class RtpDataContentDescription
: public MediaContentDescriptionImpl<RtpDataCodec> {
RtpDataContentDescription() {}
RtpDataContentDescription(const RtpDataContentDescription& o)
: MediaContentDescriptionImpl<RtpDataCodec>(o), shim_(nullptr) {}
RtpDataContentDescription& operator=(const RtpDataContentDescription& o) {
// Do not copy the shim.
return *this;
RtpDataContentDescription* Copy() const override {
return new RtpDataContentDescription(*this);
MediaType type() const override { return MEDIA_TYPE_DATA; }
RtpDataContentDescription* as_rtp_data() override { return this; }
const RtpDataContentDescription* as_rtp_data() const override { return this; }
// Shim support
DataContentDescription* as_data() override;
const DataContentDescription* as_data() const override;
std::unique_ptr<DataContentDescription> shim_;
class SctpDataContentDescription : public MediaContentDescription {
SctpDataContentDescription() {}
SctpDataContentDescription(const SctpDataContentDescription& o)
: MediaContentDescription(o),
shim_(nullptr) {}
SctpDataContentDescription* Copy() const override {
return new SctpDataContentDescription(*this);
MediaType type() const override { return MEDIA_TYPE_DATA; }
SctpDataContentDescription* as_sctp() override { return this; }
const SctpDataContentDescription* as_sctp() const override { return this; }
// Shim support
DataContentDescription* as_data() override;
const DataContentDescription* as_data() const override;
bool has_codecs() const override { return false; }
void set_protocol(const std::string& protocol) override {
protocol_ = protocol;
bool use_sctpmap() const { return use_sctpmap_; }
void set_use_sctpmap(bool enable) { use_sctpmap_ = enable; }
int port() const { return port_; }
void set_port(int port) { port_ = port; }
int max_message_size() const { return max_message_size_; }
void set_max_message_size(int max_message_size) {
max_message_size_ = max_message_size;
bool use_sctpmap_ = true; // Note: "true" is no longer conformant.
// Defaults should be constants imported from SCTP. Quick hack.
int port_ = 5000;
// draft-ietf-mmusic-sdp-sctp-23: Max message size default is 64K
int max_message_size_ = 64 * 1024;
std::unique_ptr<DataContentDescription> shim_;
// Protocol used for encoding media. This is the "top level" protocol that may
// be wrapped by zero or many transport protocols (UDP, ICE, etc.).
enum class MediaProtocolType {
kRtp, // Section will use the RTP protocol (e.g., for audio or video).
kSctp // Section will use the SCTP protocol (e.g., for a data channel).
// TODO( Remove once downstream projects have updated.
constexpr MediaProtocolType NS_JINGLE_RTP = MediaProtocolType::kRtp;
constexpr MediaProtocolType NS_JINGLE_DRAFT_SCTP = MediaProtocolType::kSctp;
// Represents a session description section. Most information about the section
// is stored in the description, which is a subclass of MediaContentDescription.
struct ContentInfo {
friend class SessionDescription;
explicit ContentInfo(MediaProtocolType type) : type(type) {}
// Alias for |name|.
std::string mid() const { return name; }
void set_mid(const std::string& mid) { this->name = mid; }
// Alias for |description|.
MediaContentDescription* media_description() { return description; }
const MediaContentDescription* media_description() const {
return description;
void set_media_description(MediaContentDescription* desc) {
description = desc;
// TODO( Rename this to mid.
std::string name;
MediaProtocolType type;
bool rejected = false;
bool bundle_only = false;
// TODO( Switch to the getter and setter, and make this
// private.
MediaContentDescription* description = nullptr;
typedef std::vector<std::string> ContentNames;
// This class provides a mechanism to aggregate different media contents into a
// group. This group can also be shared with the peers in a pre-defined format.
// GroupInfo should be populated only with the |content_name| of the
// MediaDescription.
class ContentGroup {
explicit ContentGroup(const std::string& semantics);
ContentGroup(const ContentGroup&);
ContentGroup& operator=(const ContentGroup&);
ContentGroup& operator=(ContentGroup&&);
const std::string& semantics() const { return semantics_; }
const ContentNames& content_names() const { return content_names_; }
const std::string* FirstContentName() const;
bool HasContentName(const std::string& content_name) const;
void AddContentName(const std::string& content_name);
bool RemoveContentName(const std::string& content_name);
std::string semantics_;
ContentNames content_names_;
typedef std::vector<ContentInfo> ContentInfos;
typedef std::vector<ContentGroup> ContentGroups;
const ContentInfo* FindContentInfoByName(const ContentInfos& contents,
const std::string& name);
const ContentInfo* FindContentInfoByType(const ContentInfos& contents,
const std::string& type);
// Determines how the MSID will be signaled in the SDP. These can be used as
// flags to indicate both or none.
enum MsidSignaling {
// Signal MSID with one a=msid line in the media section.
kMsidSignalingMediaSection = 0x1,
// Signal MSID with a=ssrc: msid lines in the media section.
kMsidSignalingSsrcAttribute = 0x2
// Describes a collection of contents, each with its own name and
// type. Analogous to a <jingle> or <session> stanza. Assumes that
// contents are unique be name, but doesn't enforce that.
class SessionDescription {
std::unique_ptr<SessionDescription> Clone() const;
// Older API - deprecated. Still expects caller to take ownership.
// Replace with Clone().
RTC_DEPRECATED SessionDescription* Copy() const;
struct MediaTransportSetting;
// Content accessors.
const ContentInfos& contents() const { return contents_; }
ContentInfos& contents() { return contents_; }
const ContentInfo* GetContentByName(const std::string& name) const;
ContentInfo* GetContentByName(const std::string& name);
const MediaContentDescription* GetContentDescriptionByName(
const std::string& name) const;
MediaContentDescription* GetContentDescriptionByName(const std::string& name);
const ContentInfo* FirstContentByType(MediaProtocolType type) const;
const ContentInfo* FirstContent() const;
// Content mutators.
// Adds a content to this description. Takes ownership of ContentDescription*.
void AddContent(const std::string& name,
MediaProtocolType type,
MediaContentDescription* description);
void AddContent(const std::string& name,
MediaProtocolType type,
bool rejected,
MediaContentDescription* description);
void AddContent(const std::string& name,
MediaProtocolType type,
bool rejected,
bool bundle_only,
MediaContentDescription* description);
void AddContent(ContentInfo* content);
bool RemoveContentByName(const std::string& name);
// Transport accessors.
const TransportInfos& transport_infos() const { return transport_infos_; }
TransportInfos& transport_infos() { return transport_infos_; }
const TransportInfo* GetTransportInfoByName(const std::string& name) const;
TransportInfo* GetTransportInfoByName(const std::string& name);
const TransportDescription* GetTransportDescriptionByName(
const std::string& name) const {
const TransportInfo* tinfo = GetTransportInfoByName(name);
return tinfo ? &tinfo->description : NULL;
// Transport mutators.
void set_transport_infos(const TransportInfos& transport_infos) {
transport_infos_ = transport_infos;
// Adds a TransportInfo to this description.
void AddTransportInfo(const TransportInfo& transport_info);
bool RemoveTransportInfoByName(const std::string& name);
// Group accessors.
const ContentGroups& groups() const { return content_groups_; }
const ContentGroup* GetGroupByName(const std::string& name) const;
bool HasGroup(const std::string& name) const;
// Group mutators.
void AddGroup(const ContentGroup& group) { content_groups_.push_back(group); }
// Remove the first group with the same semantics specified by |name|.
void RemoveGroupByName(const std::string& name);
// Global attributes.
void set_msid_supported(bool supported) { msid_supported_ = supported; }
bool msid_supported() const { return msid_supported_; }
// Determines how the MSIDs were/will be signaled. Flag value composed of
// MsidSignaling bits (see enum above).
void set_msid_signaling(int msid_signaling) {
msid_signaling_ = msid_signaling;
int msid_signaling() const { return msid_signaling_; }
// Determines if it's allowed to mix one- and two-byte rtp header extensions
// within the same rtp stream.
void set_extmap_allow_mixed(bool supported) {
extmap_allow_mixed_ = supported;
MediaContentDescription::ExtmapAllowMixed media_level_setting =
supported ? MediaContentDescription::kSession
: MediaContentDescription::kNo;
for (auto& content : contents_) {
// Do not set to kNo if the current setting is kMedia.
if (supported || content.media_description()->extmap_allow_mixed_enum() !=
MediaContentDescription::kMedia) {
bool extmap_allow_mixed() const { return extmap_allow_mixed_; }
// Adds the media transport setting.
// Media transport name uniquely identifies the type of media transport.
// The name cannot be empty, or repeated in the previously added transport
// settings.
void AddMediaTransportSetting(const std::string& media_transport_name,
const std::string& media_transport_setting) {
for (const auto& setting : media_transport_settings_) {
RTC_DCHECK(media_transport_name != setting.transport_name)
<< "MediaTransportSetting was already registered, transport_name="
<< setting.transport_name;
{media_transport_name, media_transport_setting});
// Gets the media transport settings, in order of preference.
const std::vector<MediaTransportSetting>& MediaTransportSettings() const {
return media_transport_settings_;
struct MediaTransportSetting {
std::string transport_name;
std::string transport_setting;
SessionDescription(const SessionDescription&);
ContentInfos contents_;
TransportInfos transport_infos_;
ContentGroups content_groups_;
bool msid_supported_ = true;
// Default to what Plan B would do.
// TODO( Change default to kMsidSignalingMediaSection.
int msid_signaling_ = kMsidSignalingSsrcAttribute;
// TODO(webrtc:9985): Activate mixed one- and two-byte header extension in
// offer at session level. It's currently not included in offer by default
// because clients prior to cannot parse this
// correctly. If it's included in offer to us we will respond that we support
// it.
bool extmap_allow_mixed_ = false;
std::vector<MediaTransportSetting> media_transport_settings_;
// Indicates whether a session description was sent by the local client or
// received from the remote client.
enum ContentSource { CS_LOCAL, CS_REMOTE };
} // namespace cricket