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 "talk/p2p/base/sessiondescription.h" 44 #include "talk/p2p/base/transport.h" 45 #include "talk/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 90 // Options to control how session descriptions are generated. 91 const int kAutoBandwidth = -1; 92 const int kBufferedModeDisabled = 0; 93 94 struct MediaSessionOptions { MediaSessionOptionsMediaSessionOptions95 MediaSessionOptions() : 96 has_audio(true), // Audio enabled by default. 97 has_video(false), 98 data_channel_type(DCT_NONE), 99 is_muc(false), 100 vad_enabled(true), // When disabled, removes all CN codecs from SDP. 101 rtcp_mux_enabled(true), 102 bundle_enabled(false), 103 video_bandwidth(kAutoBandwidth), 104 data_bandwidth(kDataMaxBandwidth) { 105 } 106 has_dataMediaSessionOptions107 bool has_data() const { return data_channel_type != DCT_NONE; } 108 109 // Add a stream with MediaType type and id. 110 // All streams with the same sync_label will get the same CNAME. 111 // All ids must be unique. 112 void AddStream(MediaType type, 113 const std::string& id, 114 const std::string& sync_label); 115 void AddVideoStream(const std::string& id, 116 const std::string& sync_label, 117 int num_sim_layers); 118 void RemoveStream(MediaType type, const std::string& id); 119 120 121 // Helper function. 122 void AddStreamInternal(MediaType type, 123 const std::string& id, 124 const std::string& sync_label, 125 int num_sim_layers); 126 127 bool has_audio; 128 bool has_video; 129 DataChannelType data_channel_type; 130 bool is_muc; 131 bool vad_enabled; 132 bool rtcp_mux_enabled; 133 bool bundle_enabled; 134 // bps. -1 == auto. 135 int video_bandwidth; 136 int data_bandwidth; 137 TransportOptions transport_options; 138 139 struct Stream { StreamMediaSessionOptions::Stream140 Stream(MediaType type, 141 const std::string& id, 142 const std::string& sync_label, 143 int num_sim_layers) 144 : type(type), id(id), sync_label(sync_label), 145 num_sim_layers(num_sim_layers) { 146 } 147 MediaType type; 148 std::string id; 149 std::string sync_label; 150 int num_sim_layers; 151 }; 152 153 typedef std::vector<Stream> Streams; 154 Streams streams; 155 }; 156 157 // "content" (as used in XEP-0166) descriptions for voice and video. 158 class MediaContentDescription : public ContentDescription { 159 public: MediaContentDescription()160 MediaContentDescription() 161 : rtcp_mux_(false), 162 bandwidth_(kAutoBandwidth), 163 crypto_required_(CT_NONE), 164 rtp_header_extensions_set_(false), 165 multistream_(false), 166 conference_mode_(false), 167 partial_(false), 168 buffered_mode_latency_(kBufferedModeDisabled), 169 direction_(MD_SENDRECV) { 170 } 171 172 virtual MediaType type() const = 0; 173 virtual bool has_codecs() const = 0; 174 175 // |protocol| is the expected media transport protocol, such as RTP/AVPF, 176 // RTP/SAVPF or SCTP/DTLS. protocol()177 std::string protocol() const { return protocol_; } set_protocol(const std::string & protocol)178 void set_protocol(const std::string& protocol) { protocol_ = protocol; } 179 direction()180 MediaContentDirection direction() const { return direction_; } set_direction(MediaContentDirection direction)181 void set_direction(MediaContentDirection direction) { 182 direction_ = direction; 183 } 184 rtcp_mux()185 bool rtcp_mux() const { return rtcp_mux_; } set_rtcp_mux(bool mux)186 void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; } 187 bandwidth()188 int bandwidth() const { return bandwidth_; } set_bandwidth(int bandwidth)189 void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } 190 cryptos()191 const std::vector<CryptoParams>& cryptos() const { return cryptos_; } AddCrypto(const CryptoParams & params)192 void AddCrypto(const CryptoParams& params) { 193 cryptos_.push_back(params); 194 } set_cryptos(const std::vector<CryptoParams> & cryptos)195 void set_cryptos(const std::vector<CryptoParams>& cryptos) { 196 cryptos_ = cryptos; 197 } 198 crypto_required()199 CryptoType crypto_required() const { return crypto_required_; } set_crypto_required(CryptoType type)200 void set_crypto_required(CryptoType type) { 201 crypto_required_ = type; 202 } 203 rtp_header_extensions()204 const RtpHeaderExtensions& rtp_header_extensions() const { 205 return rtp_header_extensions_; 206 } set_rtp_header_extensions(const RtpHeaderExtensions & extensions)207 void set_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 208 rtp_header_extensions_ = extensions; 209 rtp_header_extensions_set_ = true; 210 } AddRtpHeaderExtension(const RtpHeaderExtension & ext)211 void AddRtpHeaderExtension(const RtpHeaderExtension& ext) { 212 rtp_header_extensions_.push_back(ext); 213 rtp_header_extensions_set_ = true; 214 } ClearRtpHeaderExtensions()215 void ClearRtpHeaderExtensions() { 216 rtp_header_extensions_.clear(); 217 rtp_header_extensions_set_ = true; 218 } 219 // We can't always tell if an empty list of header extensions is 220 // because the other side doesn't support them, or just isn't hooked up to 221 // signal them. For now we assume an empty list means no signaling, but 222 // provide the ClearRtpHeaderExtensions method to allow "no support" to be 223 // clearly indicated (i.e. when derived from other information). rtp_header_extensions_set()224 bool rtp_header_extensions_set() const { 225 return rtp_header_extensions_set_; 226 } 227 // True iff the client supports multiple streams. set_multistream(bool multistream)228 void set_multistream(bool multistream) { multistream_ = multistream; } multistream()229 bool multistream() const { return multistream_; } streams()230 const StreamParamsVec& streams() const { 231 return streams_; 232 } 233 // TODO(pthatcher): Remove this by giving mediamessage.cc access 234 // to MediaContentDescription mutable_streams()235 StreamParamsVec& mutable_streams() { 236 return streams_; 237 } AddStream(const StreamParams & stream)238 void AddStream(const StreamParams& stream) { 239 streams_.push_back(stream); 240 } 241 // Legacy streams have an ssrc, but nothing else. AddLegacyStream(uint32 ssrc)242 void AddLegacyStream(uint32 ssrc) { 243 streams_.push_back(StreamParams::CreateLegacy(ssrc)); 244 } AddLegacyStream(uint32 ssrc,uint32 fid_ssrc)245 void AddLegacyStream(uint32 ssrc, uint32 fid_ssrc) { 246 StreamParams sp = StreamParams::CreateLegacy(ssrc); 247 sp.AddFidSsrc(ssrc, fid_ssrc); 248 streams_.push_back(sp); 249 } 250 // Sets the CNAME of all StreamParams if it have not been set. 251 // This can be used to set the CNAME of legacy streams. SetCnameIfEmpty(const std::string & cname)252 void SetCnameIfEmpty(const std::string& cname) { 253 for (cricket::StreamParamsVec::iterator it = streams_.begin(); 254 it != streams_.end(); ++it) { 255 if (it->cname.empty()) 256 it->cname = cname; 257 } 258 } first_ssrc()259 uint32 first_ssrc() const { 260 if (streams_.empty()) { 261 return 0; 262 } 263 return streams_[0].first_ssrc(); 264 } has_ssrcs()265 bool has_ssrcs() const { 266 if (streams_.empty()) { 267 return false; 268 } 269 return streams_[0].has_ssrcs(); 270 } 271 set_conference_mode(bool enable)272 void set_conference_mode(bool enable) { conference_mode_ = enable; } conference_mode()273 bool conference_mode() const { return conference_mode_; } 274 set_partial(bool partial)275 void set_partial(bool partial) { partial_ = partial; } partial()276 bool partial() const { return partial_; } 277 set_buffered_mode_latency(int latency)278 void set_buffered_mode_latency(int latency) { 279 buffered_mode_latency_ = latency; 280 } buffered_mode_latency()281 int buffered_mode_latency() const { return buffered_mode_latency_; } 282 283 protected: 284 bool rtcp_mux_; 285 int bandwidth_; 286 std::string protocol_; 287 std::vector<CryptoParams> cryptos_; 288 CryptoType crypto_required_; 289 std::vector<RtpHeaderExtension> rtp_header_extensions_; 290 bool rtp_header_extensions_set_; 291 bool multistream_; 292 StreamParamsVec streams_; 293 bool conference_mode_; 294 bool partial_; 295 int buffered_mode_latency_; 296 MediaContentDirection direction_; 297 }; 298 299 template <class C> 300 class MediaContentDescriptionImpl : public MediaContentDescription { 301 public: 302 struct PreferenceSort { operatorPreferenceSort303 bool operator()(C a, C b) { return a.preference > b.preference; } 304 }; 305 codecs()306 const std::vector<C>& codecs() const { return codecs_; } set_codecs(const std::vector<C> & codecs)307 void set_codecs(const std::vector<C>& codecs) { codecs_ = codecs; } has_codecs()308 virtual bool has_codecs() const { return !codecs_.empty(); } HasCodec(int id)309 bool HasCodec(int id) { 310 bool found = false; 311 for (typename std::vector<C>::iterator iter = codecs_.begin(); 312 iter != codecs_.end(); ++iter) { 313 if (iter->id == id) { 314 found = true; 315 break; 316 } 317 } 318 return found; 319 } AddCodec(const C & codec)320 void AddCodec(const C& codec) { 321 codecs_.push_back(codec); 322 } AddOrReplaceCodec(const C & codec)323 void AddOrReplaceCodec(const C& codec) { 324 for (typename std::vector<C>::iterator iter = codecs_.begin(); 325 iter != codecs_.end(); ++iter) { 326 if (iter->id == codec.id) { 327 *iter = codec; 328 return; 329 } 330 } 331 AddCodec(codec); 332 } AddCodecs(const std::vector<C> & codecs)333 void AddCodecs(const std::vector<C>& codecs) { 334 typename std::vector<C>::const_iterator codec; 335 for (codec = codecs.begin(); codec != codecs.end(); ++codec) { 336 AddCodec(*codec); 337 } 338 } SortCodecs()339 void SortCodecs() { 340 std::sort(codecs_.begin(), codecs_.end(), PreferenceSort()); 341 } 342 343 private: 344 std::vector<C> codecs_; 345 }; 346 347 class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> { 348 public: AudioContentDescription()349 AudioContentDescription() : 350 agc_minus_10db_(false) {} 351 Copy()352 virtual ContentDescription* Copy() const { 353 return new AudioContentDescription(*this); 354 } type()355 virtual MediaType type() const { return MEDIA_TYPE_AUDIO; } 356 lang()357 const std::string &lang() const { return lang_; } set_lang(const std::string & lang)358 void set_lang(const std::string &lang) { lang_ = lang; } 359 agc_minus_10db()360 bool agc_minus_10db() const { return agc_minus_10db_; } set_agc_minus_10db(bool enable)361 void set_agc_minus_10db(bool enable) { 362 agc_minus_10db_ = enable; 363 } 364 365 private: 366 bool agc_minus_10db_; 367 368 private: 369 std::string lang_; 370 }; 371 372 class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> { 373 public: Copy()374 virtual ContentDescription* Copy() const { 375 return new VideoContentDescription(*this); 376 } type()377 virtual MediaType type() const { return MEDIA_TYPE_VIDEO; } 378 }; 379 380 class DataContentDescription : public MediaContentDescriptionImpl<DataCodec> { 381 public: Copy()382 virtual ContentDescription* Copy() const { 383 return new DataContentDescription(*this); 384 } type()385 virtual MediaType type() const { return MEDIA_TYPE_DATA; } 386 }; 387 388 // Creates media session descriptions according to the supplied codecs and 389 // other fields, as well as the supplied per-call options. 390 // When creating answers, performs the appropriate negotiation 391 // of the various fields to determine the proper result. 392 class MediaSessionDescriptionFactory { 393 public: 394 // Default ctor; use methods below to set configuration. 395 // The TransportDescriptionFactory is not owned by MediaSessionDescFactory, 396 // so it must be kept alive by the user of this class. 397 explicit MediaSessionDescriptionFactory( 398 const TransportDescriptionFactory* factory); 399 // This helper automatically sets up the factory to get its configuration 400 // from the specified ChannelManager. 401 MediaSessionDescriptionFactory(ChannelManager* cmanager, 402 const TransportDescriptionFactory* factory); 403 audio_codecs()404 const AudioCodecs& audio_codecs() const { return audio_codecs_; } set_audio_codecs(const AudioCodecs & codecs)405 void set_audio_codecs(const AudioCodecs& codecs) { audio_codecs_ = codecs; } set_audio_rtp_header_extensions(const RtpHeaderExtensions & extensions)406 void set_audio_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 407 audio_rtp_extensions_ = extensions; 408 } audio_rtp_header_extensions()409 const RtpHeaderExtensions& audio_rtp_header_extensions() const { 410 return audio_rtp_extensions_; 411 } video_codecs()412 const VideoCodecs& video_codecs() const { return video_codecs_; } set_video_codecs(const VideoCodecs & codecs)413 void set_video_codecs(const VideoCodecs& codecs) { video_codecs_ = codecs; } set_video_rtp_header_extensions(const RtpHeaderExtensions & extensions)414 void set_video_rtp_header_extensions(const RtpHeaderExtensions& extensions) { 415 video_rtp_extensions_ = extensions; 416 } video_rtp_header_extensions()417 const RtpHeaderExtensions& video_rtp_header_extensions() const { 418 return video_rtp_extensions_; 419 } data_codecs()420 const DataCodecs& data_codecs() const { return data_codecs_; } set_data_codecs(const DataCodecs & codecs)421 void set_data_codecs(const DataCodecs& codecs) { data_codecs_ = codecs; } secure()422 SecurePolicy secure() const { return secure_; } set_secure(SecurePolicy s)423 void set_secure(SecurePolicy s) { secure_ = s; } 424 // Decides if a StreamParams shall be added to the audio and video media 425 // content in SessionDescription when CreateOffer and CreateAnswer is called 426 // even if |options| don't include a Stream. This is needed to support legacy 427 // applications. |add_legacy_| is true per default. set_add_legacy_streams(bool add_legacy)428 void set_add_legacy_streams(bool add_legacy) { add_legacy_ = add_legacy; } 429 430 SessionDescription* CreateOffer( 431 const MediaSessionOptions& options, 432 const SessionDescription* current_description) const; 433 SessionDescription* CreateAnswer( 434 const SessionDescription* offer, 435 const MediaSessionOptions& options, 436 const SessionDescription* current_description) const; 437 438 private: 439 void GetCodecsToOffer(const SessionDescription* current_description, 440 AudioCodecs* audio_codecs, 441 VideoCodecs* video_codecs, 442 DataCodecs* data_codecs) const; 443 void GetRtpHdrExtsToOffer(const SessionDescription* current_description, 444 RtpHeaderExtensions* audio_extensions, 445 RtpHeaderExtensions* video_extensions) const; 446 bool AddTransportOffer( 447 const std::string& content_name, 448 const TransportOptions& transport_options, 449 const SessionDescription* current_desc, 450 SessionDescription* offer) const; 451 452 TransportDescription* CreateTransportAnswer( 453 const std::string& content_name, 454 const SessionDescription* offer_desc, 455 const TransportOptions& transport_options, 456 const SessionDescription* current_desc) const; 457 458 bool AddTransportAnswer( 459 const std::string& content_name, 460 const TransportDescription& transport_desc, 461 SessionDescription* answer_desc) const; 462 463 // Helpers for adding media contents to the SessionDescription. Returns true 464 // it succeeds or the media content is not needed, or false if there is any 465 // error. 466 467 bool AddAudioContentForOffer( 468 const MediaSessionOptions& options, 469 const SessionDescription* current_description, 470 const RtpHeaderExtensions& audio_rtp_extensions, 471 const AudioCodecs& audio_codecs, 472 StreamParamsVec* current_streams, 473 SessionDescription* desc) const; 474 475 bool AddVideoContentForOffer( 476 const MediaSessionOptions& options, 477 const SessionDescription* current_description, 478 const RtpHeaderExtensions& video_rtp_extensions, 479 const VideoCodecs& video_codecs, 480 StreamParamsVec* current_streams, 481 SessionDescription* desc) const; 482 483 bool AddDataContentForOffer( 484 const MediaSessionOptions& options, 485 const SessionDescription* current_description, 486 DataCodecs* data_codecs, 487 StreamParamsVec* current_streams, 488 SessionDescription* desc) const; 489 490 bool AddAudioContentForAnswer( 491 const SessionDescription* offer, 492 const MediaSessionOptions& options, 493 const SessionDescription* current_description, 494 StreamParamsVec* current_streams, 495 SessionDescription* answer) const; 496 497 bool AddVideoContentForAnswer( 498 const SessionDescription* offer, 499 const MediaSessionOptions& options, 500 const SessionDescription* current_description, 501 StreamParamsVec* current_streams, 502 SessionDescription* answer) const; 503 504 bool AddDataContentForAnswer( 505 const SessionDescription* offer, 506 const MediaSessionOptions& options, 507 const SessionDescription* current_description, 508 StreamParamsVec* current_streams, 509 SessionDescription* answer) const; 510 511 AudioCodecs audio_codecs_; 512 RtpHeaderExtensions audio_rtp_extensions_; 513 VideoCodecs video_codecs_; 514 RtpHeaderExtensions video_rtp_extensions_; 515 DataCodecs data_codecs_; 516 SecurePolicy secure_; 517 bool add_legacy_; 518 std::string lang_; 519 const TransportDescriptionFactory* transport_desc_factory_; 520 }; 521 522 // Convenience functions. 523 bool IsMediaContent(const ContentInfo* content); 524 bool IsAudioContent(const ContentInfo* content); 525 bool IsVideoContent(const ContentInfo* content); 526 bool IsDataContent(const ContentInfo* content); 527 const ContentInfo* GetFirstAudioContent(const ContentInfos& contents); 528 const ContentInfo* GetFirstVideoContent(const ContentInfos& contents); 529 const ContentInfo* GetFirstDataContent(const ContentInfos& contents); 530 const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc); 531 const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc); 532 const ContentInfo* GetFirstDataContent(const SessionDescription* sdesc); 533 const AudioContentDescription* GetFirstAudioContentDescription( 534 const SessionDescription* sdesc); 535 const VideoContentDescription* GetFirstVideoContentDescription( 536 const SessionDescription* sdesc); 537 const DataContentDescription* GetFirstDataContentDescription( 538 const SessionDescription* sdesc); 539 bool GetStreamBySsrc( 540 const SessionDescription* sdesc, MediaType media_type, 541 uint32 ssrc, StreamParams* stream_out); 542 bool GetStreamByIds( 543 const SessionDescription* sdesc, MediaType media_type, 544 const std::string& groupid, const std::string& id, 545 StreamParams* stream_out); 546 547 // Functions for translating media candidate names. 548 549 // For converting between media ICE component and G-ICE channel 550 // names. For example: 551 // "rtp" <=> 1 552 // "rtcp" <=> 2 553 // "video_rtp" <=> 1 554 // "video_rtcp" <=> 2 555 // Will not convert in the general case of arbitrary channel names, 556 // but is useful for cases where we have candidates for media 557 // channels. 558 // returns false if there is no mapping. 559 bool GetMediaChannelNameFromComponent( 560 int component, cricket::MediaType media_type, std::string* channel_name); 561 bool GetMediaComponentFromChannelName( 562 const std::string& channel_name, int* component); 563 bool GetMediaTypeFromChannelName( 564 const std::string& channel_name, cricket::MediaType* media_type); 565 566 void GetSupportedAudioCryptoSuites(std::vector<std::string>* crypto_suites); 567 void GetSupportedVideoCryptoSuites(std::vector<std::string>* crypto_suites); 568 void GetSupportedDataCryptoSuites(std::vector<std::string>* crypto_suites); 569 void GetSupportedDefaultCryptoSuites(std::vector<std::string>* crypto_suites); 570 } // namespace cricket 571 572 #endif // TALK_SESSION_MEDIA_MEDIASESSION_H_ 573