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