1 /* 2 * libjingle 3 * Copyright 2004 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // Types and classes used in media session descriptions. 29 30 #ifndef TALK_SESSION_MEDIA_MEDIASESSION_H_ 31 #define TALK_SESSION_MEDIA_MEDIASESSION_H_ 32 33 #include <algorithm> 34 #include <string> 35 #include <vector> 36 37 #include "talk/media/base/codec.h" 38 #include "talk/media/base/constants.h" 39 #include "talk/media/base/cryptoparams.h" 40 #include "talk/media/base/mediachannel.h" 41 #include "talk/media/base/mediaengine.h" // For DataChannelType 42 #include "talk/media/base/streamparams.h" 43 #include "webrtc/p2p/base/sessiondescription.h" 44 #include "webrtc/p2p/base/transport.h" 45 #include "webrtc/p2p/base/transportdescriptionfactory.h" 46 #include "webrtc/base/scoped_ptr.h" 47 48 namespace cricket { 49 50 class ChannelManager; 51 typedef std::vector<AudioCodec> AudioCodecs; 52 typedef std::vector<VideoCodec> VideoCodecs; 53 typedef std::vector<DataCodec> DataCodecs; 54 typedef std::vector<CryptoParams> CryptoParamsVec; 55 typedef std::vector<RtpHeaderExtension> RtpHeaderExtensions; 56 57 enum MediaType { 58 MEDIA_TYPE_AUDIO, 59 MEDIA_TYPE_VIDEO, 60 MEDIA_TYPE_DATA 61 }; 62 63 std::string MediaTypeToString(MediaType type); 64 65 enum MediaContentDirection { 66 MD_INACTIVE, 67 MD_SENDONLY, 68 MD_RECVONLY, 69 MD_SENDRECV 70 }; 71 72 enum CryptoType { 73 CT_NONE, 74 CT_SDES, 75 CT_DTLS 76 }; 77 78 // RTC4585 RTP/AVPF 79 extern const char kMediaProtocolAvpf[]; 80 // RFC5124 RTP/SAVPF 81 extern const char kMediaProtocolSavpf[]; 82 83 extern const char kMediaProtocolDtlsSavpf[]; 84 85 extern const char kMediaProtocolRtpPrefix[]; 86 87 extern const char kMediaProtocolSctp[]; 88 extern const char kMediaProtocolDtlsSctp[]; 89 extern const char kMediaProtocolUdpDtlsSctp[]; 90 extern const char kMediaProtocolTcpDtlsSctp[]; 91 92 // Options to control how session descriptions are generated. 93 const int kAutoBandwidth = -1; 94 const int kBufferedModeDisabled = 0; 95 96 struct MediaSessionOptions { MediaSessionOptionsMediaSessionOptions97 MediaSessionOptions() : 98 recv_audio(true), 99 recv_video(false), 100 data_channel_type(DCT_NONE), 101 is_muc(false), 102 vad_enabled(true), // When disabled, removes all CN codecs from SDP. 103 rtcp_mux_enabled(true), 104 bundle_enabled(false), 105 video_bandwidth(kAutoBandwidth), 106 data_bandwidth(kDataMaxBandwidth) { 107 } 108 has_audioMediaSessionOptions109 bool has_audio() const { 110 return recv_audio || HasSendMediaStream(MEDIA_TYPE_AUDIO); 111 } has_videoMediaSessionOptions112 bool has_video() const { 113 return recv_video || HasSendMediaStream(MEDIA_TYPE_VIDEO); 114 } has_dataMediaSessionOptions115 bool has_data() const { return data_channel_type != DCT_NONE; } 116 117 // Add a stream with MediaType type and id. 118 // All streams with the same sync_label will get the same CNAME. 119 // All ids must be unique. 120 void AddSendStream(MediaType type, 121 const std::string& id, 122 const std::string& sync_label); 123 void AddSendVideoStream(const std::string& id, 124 const std::string& sync_label, 125 int num_sim_layers); 126 void RemoveSendStream(MediaType type, const std::string& id); 127 128 129 // Helper function. 130 void AddSendStreamInternal(MediaType type, 131 const std::string& id, 132 const std::string& sync_label, 133 int num_sim_layers); 134 135 bool HasSendMediaStream(MediaType type) const; 136 137 // TODO(deadbeef): Put all the audio/video/data-specific options into a map 138 // structure (content name -> options). 139 // MediaSessionDescriptionFactory assumes there will never be more than one 140 // audio/video/data content, but this will change with unified plan. 141 bool recv_audio; 142 bool recv_video; 143 DataChannelType data_channel_type; 144 bool is_muc; 145 bool vad_enabled; 146 bool rtcp_mux_enabled; 147 bool bundle_enabled; 148 // bps. -1 == auto. 149 int video_bandwidth; 150 int data_bandwidth; 151 TransportOptions audio_transport_options; 152 TransportOptions video_transport_options; 153 TransportOptions data_transport_options; 154 155 struct Stream { StreamMediaSessionOptions::Stream156 Stream(MediaType type, 157 const std::string& id, 158 const std::string& sync_label, 159 int num_sim_layers) 160 : type(type), id(id), sync_label(sync_label), 161 num_sim_layers(num_sim_layers) { 162 } 163 MediaType type; 164 std::string id; 165 std::string sync_label; 166 int num_sim_layers; 167 }; 168 169 typedef std::vector<Stream> Streams; 170 Streams streams; 171 }; 172 173 // "content" (as used in XEP-0166) descriptions for voice and video. 174 class MediaContentDescription : public ContentDescription { 175 public: MediaContentDescription()176 MediaContentDescription() {} 177 178 virtual MediaType type() const = 0; 179 virtual bool has_codecs() const = 0; 180 181 // |protocol| is the expected media transport protocol, such as RTP/AVPF, 182 // RTP/SAVPF or SCTP/DTLS. protocol()183 std::string protocol() const { return protocol_; } set_protocol(const std::string & protocol)184 void set_protocol(const std::string& protocol) { protocol_ = protocol; } 185 direction()186 MediaContentDirection direction() const { return direction_; } set_direction(MediaContentDirection direction)187 void set_direction(MediaContentDirection direction) { 188 direction_ = direction; 189 } 190 rtcp_mux()191 bool rtcp_mux() const { return rtcp_mux_; } set_rtcp_mux(bool mux)192 void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } 193 rtcp_reduced_size()194 bool rtcp_reduced_size() const { return rtcp_reduced_size_; } set_rtcp_reduced_size(bool reduced_size)195 void set_rtcp_reduced_size(bool reduced_size) { 196 rtcp_reduced_size_ = reduced_size; 197 } 198 bandwidth()199 int bandwidth() const { return bandwidth_; } set_bandwidth(int bandwidth)200 void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } 201 cryptos()202 const std::vector<CryptoParams>& cryptos() const { return cryptos_; } AddCrypto(const CryptoParams & params)203 void AddCrypto(const CryptoParams& params) { 204 cryptos_.push_back(params); 205 } set_cryptos(const std::vector<CryptoParams> & cryptos)206 void set_cryptos(const std::vector<CryptoParams>& cryptos) { 207 cryptos_ = cryptos; 208 } 209 crypto_required()210 CryptoType crypto_required() const { return crypto_required_; } set_crypto_required(CryptoType type)211 void set_crypto_required(CryptoType type) { 212 crypto_required_ = type; 213 } 214 rtp_header_extensions()215 const RtpHeaderExtensions& rtp_header_extensions() const { 216 return rtp_header_extensions_; 217 } set_rtp_header_extensions(const RtpHeaderExtensions & extensions)218 void set_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 219 rtp_header_extensions_ = extensions; 220 rtp_header_extensions_set_ = true; 221 } AddRtpHeaderExtension(const RtpHeaderExtension & ext)222 void AddRtpHeaderExtension(const RtpHeaderExtension& ext) { 223 rtp_header_extensions_.push_back(ext); 224 rtp_header_extensions_set_ = true; 225 } ClearRtpHeaderExtensions()226 void ClearRtpHeaderExtensions() { 227 rtp_header_extensions_.clear(); 228 rtp_header_extensions_set_ = true; 229 } 230 // We can't always tell if an empty list of header extensions is 231 // because the other side doesn't support them, or just isn't hooked up to 232 // signal them. For now we assume an empty list means no signaling, but 233 // provide the ClearRtpHeaderExtensions method to allow "no support" to be 234 // clearly indicated (i.e. when derived from other information). rtp_header_extensions_set()235 bool rtp_header_extensions_set() const { 236 return rtp_header_extensions_set_; 237 } 238 // True iff the client supports multiple streams. set_multistream(bool multistream)239 void set_multistream(bool multistream) { multistream_ = multistream; } multistream()240 bool multistream() const { return multistream_; } streams()241 const StreamParamsVec& streams() const { 242 return streams_; 243 } 244 // TODO(pthatcher): Remove this by giving mediamessage.cc access 245 // to MediaContentDescription mutable_streams()246 StreamParamsVec& mutable_streams() { 247 return streams_; 248 } AddStream(const StreamParams & stream)249 void AddStream(const StreamParams& stream) { 250 streams_.push_back(stream); 251 } 252 // Legacy streams have an ssrc, but nothing else. AddLegacyStream(uint32_t ssrc)253 void AddLegacyStream(uint32_t ssrc) { 254 streams_.push_back(StreamParams::CreateLegacy(ssrc)); 255 } AddLegacyStream(uint32_t ssrc,uint32_t fid_ssrc)256 void AddLegacyStream(uint32_t ssrc, uint32_t fid_ssrc) { 257 StreamParams sp = StreamParams::CreateLegacy(ssrc); 258 sp.AddFidSsrc(ssrc, fid_ssrc); 259 streams_.push_back(sp); 260 } 261 // Sets the CNAME of all StreamParams if it have not been set. 262 // This can be used to set the CNAME of legacy streams. SetCnameIfEmpty(const std::string & cname)263 void SetCnameIfEmpty(const std::string& cname) { 264 for (cricket::StreamParamsVec::iterator it = streams_.begin(); 265 it != streams_.end(); ++it) { 266 if (it->cname.empty()) 267 it->cname = cname; 268 } 269 } first_ssrc()270 uint32_t first_ssrc() const { 271 if (streams_.empty()) { 272 return 0; 273 } 274 return streams_[0].first_ssrc(); 275 } has_ssrcs()276 bool has_ssrcs() const { 277 if (streams_.empty()) { 278 return false; 279 } 280 return streams_[0].has_ssrcs(); 281 } 282 set_conference_mode(bool enable)283 void set_conference_mode(bool enable) { conference_mode_ = enable; } conference_mode()284 bool conference_mode() const { return conference_mode_; } 285 set_partial(bool partial)286 void set_partial(bool partial) { partial_ = partial; } partial()287 bool partial() const { return partial_; } 288 set_buffered_mode_latency(int latency)289 void set_buffered_mode_latency(int latency) { 290 buffered_mode_latency_ = latency; 291 } buffered_mode_latency()292 int buffered_mode_latency() const { return buffered_mode_latency_; } 293 294 protected: 295 bool rtcp_mux_ = false; 296 bool rtcp_reduced_size_ = false; 297 int bandwidth_ = kAutoBandwidth; 298 std::string protocol_; 299 std::vector<CryptoParams> cryptos_; 300 CryptoType crypto_required_ = CT_NONE; 301 std::vector<RtpHeaderExtension> rtp_header_extensions_; 302 bool rtp_header_extensions_set_ = false; 303 bool multistream_ = false; 304 StreamParamsVec streams_; 305 bool conference_mode_ = false; 306 bool partial_ = false; 307 int buffered_mode_latency_ = kBufferedModeDisabled; 308 MediaContentDirection direction_ = MD_SENDRECV; 309 }; 310 311 template <class C> 312 class MediaContentDescriptionImpl : public MediaContentDescription { 313 public: 314 struct PreferenceSort { operatorPreferenceSort315 bool operator()(C a, C b) { return a.preference > b.preference; } 316 }; 317 codecs()318 const std::vector<C>& codecs() const { return codecs_; } set_codecs(const std::vector<C> & codecs)319 void set_codecs(const std::vector<C>& codecs) { codecs_ = codecs; } has_codecs()320 virtual bool has_codecs() const { return !codecs_.empty(); } HasCodec(int id)321 bool HasCodec(int id) { 322 bool found = false; 323 for (typename std::vector<C>::iterator iter = codecs_.begin(); 324 iter != codecs_.end(); ++iter) { 325 if (iter->id == id) { 326 found = true; 327 break; 328 } 329 } 330 return found; 331 } AddCodec(const C & codec)332 void AddCodec(const C& codec) { 333 codecs_.push_back(codec); 334 } AddOrReplaceCodec(const C & codec)335 void AddOrReplaceCodec(const C& codec) { 336 for (typename std::vector<C>::iterator iter = codecs_.begin(); 337 iter != codecs_.end(); ++iter) { 338 if (iter->id == codec.id) { 339 *iter = codec; 340 return; 341 } 342 } 343 AddCodec(codec); 344 } AddCodecs(const std::vector<C> & codecs)345 void AddCodecs(const std::vector<C>& codecs) { 346 typename std::vector<C>::const_iterator codec; 347 for (codec = codecs.begin(); codec != codecs.end(); ++codec) { 348 AddCodec(*codec); 349 } 350 } SortCodecs()351 void SortCodecs() { 352 std::sort(codecs_.begin(), codecs_.end(), PreferenceSort()); 353 } 354 355 private: 356 std::vector<C> codecs_; 357 }; 358 359 class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> { 360 public: AudioContentDescription()361 AudioContentDescription() : 362 agc_minus_10db_(false) {} 363 Copy()364 virtual ContentDescription* Copy() const { 365 return new AudioContentDescription(*this); 366 } type()367 virtual MediaType type() const { return MEDIA_TYPE_AUDIO; } 368 lang()369 const std::string &lang() const { return lang_; } set_lang(const std::string & lang)370 void set_lang(const std::string &lang) { lang_ = lang; } 371 agc_minus_10db()372 bool agc_minus_10db() const { return agc_minus_10db_; } set_agc_minus_10db(bool enable)373 void set_agc_minus_10db(bool enable) { 374 agc_minus_10db_ = enable; 375 } 376 377 private: 378 bool agc_minus_10db_; 379 380 private: 381 std::string lang_; 382 }; 383 384 class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> { 385 public: Copy()386 virtual ContentDescription* Copy() const { 387 return new VideoContentDescription(*this); 388 } type()389 virtual MediaType type() const { return MEDIA_TYPE_VIDEO; } 390 }; 391 392 class DataContentDescription : public MediaContentDescriptionImpl<DataCodec> { 393 public: Copy()394 virtual ContentDescription* Copy() const { 395 return new DataContentDescription(*this); 396 } type()397 virtual MediaType type() const { return MEDIA_TYPE_DATA; } 398 }; 399 400 // Creates media session descriptions according to the supplied codecs and 401 // other fields, as well as the supplied per-call options. 402 // When creating answers, performs the appropriate negotiation 403 // of the various fields to determine the proper result. 404 class MediaSessionDescriptionFactory { 405 public: 406 // Default ctor; use methods below to set configuration. 407 // The TransportDescriptionFactory is not owned by MediaSessionDescFactory, 408 // so it must be kept alive by the user of this class. 409 explicit MediaSessionDescriptionFactory( 410 const TransportDescriptionFactory* factory); 411 // This helper automatically sets up the factory to get its configuration 412 // from the specified ChannelManager. 413 MediaSessionDescriptionFactory(ChannelManager* cmanager, 414 const TransportDescriptionFactory* factory); 415 audio_codecs()416 const AudioCodecs& audio_codecs() const { return audio_codecs_; } set_audio_codecs(const AudioCodecs & codecs)417 void set_audio_codecs(const AudioCodecs& codecs) { audio_codecs_ = codecs; } set_audio_rtp_header_extensions(const RtpHeaderExtensions & extensions)418 void set_audio_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 419 audio_rtp_extensions_ = extensions; 420 } audio_rtp_header_extensions()421 const RtpHeaderExtensions& audio_rtp_header_extensions() const { 422 return audio_rtp_extensions_; 423 } video_codecs()424 const VideoCodecs& video_codecs() const { return video_codecs_; } set_video_codecs(const VideoCodecs & codecs)425 void set_video_codecs(const VideoCodecs& codecs) { video_codecs_ = codecs; } set_video_rtp_header_extensions(const RtpHeaderExtensions & extensions)426 void set_video_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 427 video_rtp_extensions_ = extensions; 428 } video_rtp_header_extensions()429 const RtpHeaderExtensions& video_rtp_header_extensions() const { 430 return video_rtp_extensions_; 431 } data_codecs()432 const DataCodecs& data_codecs() const { return data_codecs_; } set_data_codecs(const DataCodecs & codecs)433 void set_data_codecs(const DataCodecs& codecs) { data_codecs_ = codecs; } secure()434 SecurePolicy secure() const { return secure_; } set_secure(SecurePolicy s)435 void set_secure(SecurePolicy s) { secure_ = s; } 436 // Decides if a StreamParams shall be added to the audio and video media 437 // content in SessionDescription when CreateOffer and CreateAnswer is called 438 // even if |options| don't include a Stream. This is needed to support legacy 439 // applications. |add_legacy_| is true per default. set_add_legacy_streams(bool add_legacy)440 void set_add_legacy_streams(bool add_legacy) { add_legacy_ = add_legacy; } 441 442 SessionDescription* CreateOffer( 443 const MediaSessionOptions& options, 444 const SessionDescription* current_description) const; 445 SessionDescription* CreateAnswer( 446 const SessionDescription* offer, 447 const MediaSessionOptions& options, 448 const SessionDescription* current_description) const; 449 450 private: 451 void GetCodecsToOffer(const SessionDescription* current_description, 452 AudioCodecs* audio_codecs, 453 VideoCodecs* video_codecs, 454 DataCodecs* data_codecs) const; 455 void GetRtpHdrExtsToOffer(const SessionDescription* current_description, 456 RtpHeaderExtensions* audio_extensions, 457 RtpHeaderExtensions* video_extensions) const; 458 bool AddTransportOffer( 459 const std::string& content_name, 460 const TransportOptions& transport_options, 461 const SessionDescription* current_desc, 462 SessionDescription* offer) const; 463 464 TransportDescription* CreateTransportAnswer( 465 const std::string& content_name, 466 const SessionDescription* offer_desc, 467 const TransportOptions& transport_options, 468 const SessionDescription* current_desc) const; 469 470 bool AddTransportAnswer( 471 const std::string& content_name, 472 const TransportDescription& transport_desc, 473 SessionDescription* answer_desc) const; 474 475 // Helpers for adding media contents to the SessionDescription. Returns true 476 // it succeeds or the media content is not needed, or false if there is any 477 // error. 478 479 bool AddAudioContentForOffer( 480 const MediaSessionOptions& options, 481 const SessionDescription* current_description, 482 const RtpHeaderExtensions& audio_rtp_extensions, 483 const AudioCodecs& audio_codecs, 484 StreamParamsVec* current_streams, 485 SessionDescription* desc) const; 486 487 bool AddVideoContentForOffer( 488 const MediaSessionOptions& options, 489 const SessionDescription* current_description, 490 const RtpHeaderExtensions& video_rtp_extensions, 491 const VideoCodecs& video_codecs, 492 StreamParamsVec* current_streams, 493 SessionDescription* desc) const; 494 495 bool AddDataContentForOffer( 496 const MediaSessionOptions& options, 497 const SessionDescription* current_description, 498 DataCodecs* data_codecs, 499 StreamParamsVec* current_streams, 500 SessionDescription* desc) const; 501 502 bool AddAudioContentForAnswer( 503 const SessionDescription* offer, 504 const MediaSessionOptions& options, 505 const SessionDescription* current_description, 506 StreamParamsVec* current_streams, 507 SessionDescription* answer) const; 508 509 bool AddVideoContentForAnswer( 510 const SessionDescription* offer, 511 const MediaSessionOptions& options, 512 const SessionDescription* current_description, 513 StreamParamsVec* current_streams, 514 SessionDescription* answer) const; 515 516 bool AddDataContentForAnswer( 517 const SessionDescription* offer, 518 const MediaSessionOptions& options, 519 const SessionDescription* current_description, 520 StreamParamsVec* current_streams, 521 SessionDescription* answer) const; 522 523 AudioCodecs audio_codecs_; 524 RtpHeaderExtensions audio_rtp_extensions_; 525 VideoCodecs video_codecs_; 526 RtpHeaderExtensions video_rtp_extensions_; 527 DataCodecs data_codecs_; 528 SecurePolicy secure_; 529 bool add_legacy_; 530 std::string lang_; 531 const TransportDescriptionFactory* transport_desc_factory_; 532 }; 533 534 // Convenience functions. 535 bool IsMediaContent(const ContentInfo* content); 536 bool IsAudioContent(const ContentInfo* content); 537 bool IsVideoContent(const ContentInfo* content); 538 bool IsDataContent(const ContentInfo* content); 539 const ContentInfo* GetFirstAudioContent(const ContentInfos& contents); 540 const ContentInfo* GetFirstVideoContent(const ContentInfos& contents); 541 const ContentInfo* GetFirstDataContent(const ContentInfos& contents); 542 const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc); 543 const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc); 544 const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc); 545 const AudioContentDescription* GetFirstAudioContentDescription( 546 const SessionDescription* sdesc); 547 const VideoContentDescription* GetFirstVideoContentDescription( 548 const SessionDescription* sdesc); 549 const DataContentDescription* GetFirstDataContentDescription( 550 const SessionDescription* sdesc); 551 552 void GetSupportedAudioCryptoSuites(std::vector<int>* crypto_suites); 553 void GetSupportedVideoCryptoSuites(std::vector<int>* crypto_suites); 554 void GetSupportedDataCryptoSuites(std::vector<int>* crypto_suites); 555 void GetDefaultSrtpCryptoSuites(std::vector<int>* crypto_suites); 556 void GetSupportedAudioCryptoSuiteNames( 557 std::vector<std::string>* crypto_suite_names); 558 void GetSupportedVideoCryptoSuiteNames( 559 std::vector<std::string>* crypto_suite_names); 560 void GetSupportedDataCryptoSuiteNames( 561 std::vector<std::string>* crypto_suite_names); 562 void GetDefaultSrtpCryptoSuiteNames( 563 std::vector<std::string>* crypto_suite_names); 564 565 } // namespace cricket 566 567 #endif // TALK_SESSION_MEDIA_MEDIASESSION_H_ 568