OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2004 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 it != crypto_suites.end(); ++it) { | 152 it != crypto_suites.end(); ++it) { |
153 if (!AddCryptoParams(*it, &cryptos)) { | 153 if (!AddCryptoParams(*it, &cryptos)) { |
154 return false; | 154 return false; |
155 } | 155 } |
156 } | 156 } |
157 AddMediaCryptos(cryptos, media); | 157 AddMediaCryptos(cryptos, media); |
158 return true; | 158 return true; |
159 } | 159 } |
160 #endif | 160 #endif |
161 | 161 |
162 const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) { | 162 const CryptoParamsVec* GetCryptos(const ContentInfo* content) { |
163 if (!media) { | 163 if (!content) { |
164 return NULL; | 164 return nullptr; |
165 } | 165 } |
166 return &media->cryptos(); | 166 return &(static_cast<const MediaContentDescription*>(content->description) |
| 167 ->cryptos()); |
167 } | 168 } |
168 | 169 |
169 bool FindMatchingCrypto(const CryptoParamsVec& cryptos, | 170 bool FindMatchingCrypto(const CryptoParamsVec& cryptos, |
170 const CryptoParams& crypto, | 171 const CryptoParams& crypto, |
171 CryptoParams* out) { | 172 CryptoParams* out) { |
172 for (CryptoParamsVec::const_iterator it = cryptos.begin(); | 173 for (CryptoParamsVec::const_iterator it = cryptos.begin(); |
173 it != cryptos.end(); ++it) { | 174 it != cryptos.end(); ++it) { |
174 if (crypto.Matches(*it)) { | 175 if (crypto.Matches(*it)) { |
175 *out = *it; | 176 *out = *it; |
176 return true; | 177 return true; |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 } | 326 } |
326 | 327 |
327 // Loops through all Id in |ids| and changes its id if it is | 328 // Loops through all Id in |ids| and changes its id if it is |
328 // already in use by another IdStruct. Call this methods with all Id | 329 // already in use by another IdStruct. Call this methods with all Id |
329 // in a session description to make sure no duplicate ids exists. | 330 // in a session description to make sure no duplicate ids exists. |
330 // Note that typename Id must be a type of IdStruct. | 331 // Note that typename Id must be a type of IdStruct. |
331 template <typename Id> | 332 template <typename Id> |
332 void FindAndSetIdUsed(std::vector<Id>* ids) { | 333 void FindAndSetIdUsed(std::vector<Id>* ids) { |
333 for (typename std::vector<Id>::iterator it = ids->begin(); | 334 for (typename std::vector<Id>::iterator it = ids->begin(); |
334 it != ids->end(); ++it) { | 335 it != ids->end(); ++it) { |
335 FindAndSetIdUsed(&*it); | 336 FindAndSetIdUsed(&*it, true); |
336 } | 337 } |
337 } | 338 } |
338 | 339 |
339 // Finds and sets an unused id if the |idstruct| id is already in use. | 340 // Finds and sets an unused id if the |idstruct| id is already in use. |
340 void FindAndSetIdUsed(IdStruct* idstruct) { | 341 // If |can_reassign_id| is false, the ID of |idstruct| won't be reassigned, |
| 342 // and ID conflicts will simply result in false being returned. |
| 343 bool FindAndSetIdUsed(IdStruct* idstruct, bool can_reassign_id) { |
341 const int original_id = idstruct->id; | 344 const int original_id = idstruct->id; |
342 int new_id = idstruct->id; | 345 int new_id = idstruct->id; |
343 | 346 |
344 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) { | 347 if (original_id > max_allowed_id_ || original_id < min_allowed_id_) { |
345 // If the original id is not in range - this is an id that can't be | 348 // If the original id is not in range - this is an id that can't be |
346 // dynamically changed. | 349 // dynamically changed. |
347 return; | 350 return true; |
348 } | 351 } |
349 | 352 |
350 if (IsIdUsed(original_id)) { | 353 if (IsIdUsed(original_id)) { |
| 354 if (!can_reassign_id) { |
| 355 return false; |
| 356 } |
351 new_id = FindUnusedId(); | 357 new_id = FindUnusedId(); |
352 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id | 358 LOG(LS_WARNING) << "Duplicate id found. Reassigning from " << original_id |
353 << " to " << new_id; | 359 << " to " << new_id; |
354 idstruct->id = new_id; | 360 idstruct->id = new_id; |
355 } | 361 } |
356 SetIdUsed(new_id); | 362 SetIdUsed(new_id); |
| 363 return true; |
357 } | 364 } |
358 | 365 |
359 private: | 366 private: |
360 // Returns the first unused id in reverse order. | 367 // Returns the first unused id in reverse order. |
361 // This hopefully reduce the risk of more collisions. We want to change the | 368 // This hopefully reduce the risk of more collisions. We want to change the |
362 // default ids as little as possible. | 369 // default ids as little as possible. |
363 int FindUnusedId() { | 370 int FindUnusedId() { |
364 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) { | 371 while (IsIdUsed(next_id_) && next_id_ >= min_allowed_id_) { |
365 --next_id_; | 372 --next_id_; |
366 } | 373 } |
(...skipping 16 matching lines...) Expand all Loading... |
383 }; | 390 }; |
384 | 391 |
385 // Helper class used for finding duplicate RTP payload types among audio, video | 392 // Helper class used for finding duplicate RTP payload types among audio, video |
386 // and data codecs. When bundle is used the payload types may not collide. | 393 // and data codecs. When bundle is used the payload types may not collide. |
387 class UsedPayloadTypes : public UsedIds<Codec> { | 394 class UsedPayloadTypes : public UsedIds<Codec> { |
388 public: | 395 public: |
389 UsedPayloadTypes() | 396 UsedPayloadTypes() |
390 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) { | 397 : UsedIds<Codec>(kDynamicPayloadTypeMin, kDynamicPayloadTypeMax) { |
391 } | 398 } |
392 | 399 |
393 | |
394 private: | 400 private: |
395 static const int kDynamicPayloadTypeMin = 96; | 401 static const int kDynamicPayloadTypeMin = 96; |
396 static const int kDynamicPayloadTypeMax = 127; | 402 static const int kDynamicPayloadTypeMax = 127; |
397 }; | 403 }; |
398 | 404 |
399 // Helper class used for finding duplicate RTP Header extension ids among | 405 // Helper class used for finding duplicate RTP Header extension ids among |
400 // audio and video extensions. | 406 // audio and video extensions. |
401 class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> { | 407 class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> { |
402 public: | 408 public: |
403 UsedRtpHeaderExtensionIds() | 409 UsedRtpHeaderExtensionIds() |
404 : UsedIds<webrtc::RtpExtension>(kLocalIdMin, kLocalIdMax) {} | 410 : UsedIds<webrtc::RtpExtension>(kLocalIdMin, kLocalIdMax) {} |
405 | 411 |
406 private: | 412 private: |
407 // Min and Max local identifier for one-byte header extensions, per RFC5285. | 413 // Min and Max local identifier for one-byte header extensions, per RFC5285. |
408 static const int kLocalIdMin = 1; | 414 static const int kLocalIdMin = 1; |
409 static const int kLocalIdMax = 14; | 415 static const int kLocalIdMax = 14; |
410 }; | 416 }; |
411 | 417 |
412 static bool IsSctp(const MediaContentDescription* desc) { | 418 static bool IsSctp(const MediaContentDescription* desc) { |
413 return ((desc->protocol() == kMediaProtocolSctp) || | 419 return ((desc->protocol() == kMediaProtocolSctp) || |
414 (desc->protocol() == kMediaProtocolDtlsSctp)); | 420 (desc->protocol() == kMediaProtocolDtlsSctp)); |
415 } | 421 } |
416 | 422 |
417 // Adds a StreamParams for each Stream in Streams with media type | 423 // Adds a StreamParams for each SenderOptions in |sender_options| to |
418 // media_type to content_description. | 424 // content_description. |
419 // |current_params| - All currently known StreamParams of any media type. | 425 // |current_params| - All currently known StreamParams. |
420 template <class C> | 426 template <class C> |
421 static bool AddStreamParams(MediaType media_type, | 427 static bool AddStreamParams( |
422 const MediaSessionOptions& options, | 428 const std::vector<SenderOptions>& sender_options, |
423 StreamParamsVec* current_streams, | 429 const std::string& rtcp_cname, |
424 MediaContentDescriptionImpl<C>* content_description, | 430 StreamParamsVec* current_streams, |
425 const bool add_legacy_stream) { | 431 MediaContentDescriptionImpl<C>* content_description) { |
426 // SCTP streams are not negotiated using SDP/ContentDescriptions. | 432 // SCTP streams are not negotiated using SDP/ContentDescriptions. |
427 if (IsSctp(content_description)) { | 433 if (IsSctp(content_description)) { |
428 return true; | 434 return true; |
429 } | 435 } |
430 | 436 |
431 const bool include_rtx_streams = | 437 const bool include_rtx_streams = |
432 ContainsRtxCodec(content_description->codecs()); | 438 ContainsRtxCodec(content_description->codecs()); |
433 | 439 |
434 const MediaSessionOptions::Streams& streams = options.streams; | |
435 if (streams.empty() && add_legacy_stream) { | |
436 // TODO(perkj): Remove this legacy stream when all apps use StreamParams. | |
437 std::vector<uint32_t> ssrcs; | |
438 int num_ssrcs = include_rtx_streams ? 2 : 1; | |
439 GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs); | |
440 if (include_rtx_streams) { | |
441 content_description->AddLegacyStream(ssrcs[0], ssrcs[1]); | |
442 content_description->set_multistream(true); | |
443 } else { | |
444 content_description->AddLegacyStream(ssrcs[0]); | |
445 } | |
446 return true; | |
447 } | |
448 | |
449 const bool include_flexfec_stream = | 440 const bool include_flexfec_stream = |
450 ContainsFlexfecCodec(content_description->codecs()); | 441 ContainsFlexfecCodec(content_description->codecs()); |
451 | 442 |
452 MediaSessionOptions::Streams::const_iterator stream_it; | 443 for (const SenderOptions& sender : sender_options) { |
453 for (stream_it = streams.begin(); | |
454 stream_it != streams.end(); ++stream_it) { | |
455 if (stream_it->type != media_type) | |
456 continue; // Wrong media type. | |
457 | |
458 const StreamParams* param = | |
459 GetStreamByIds(*current_streams, "", stream_it->id); | |
460 // groupid is empty for StreamParams generated using | 444 // groupid is empty for StreamParams generated using |
461 // MediaSessionDescriptionFactory. | 445 // MediaSessionDescriptionFactory. |
| 446 const StreamParams* param = |
| 447 GetStreamByIds(*current_streams, "", sender.track_id); |
462 if (!param) { | 448 if (!param) { |
463 // This is a new stream. | 449 // This is a new sender. |
464 std::vector<uint32_t> ssrcs; | 450 std::vector<uint32_t> ssrcs; |
465 GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs); | 451 GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs); |
466 StreamParams stream_param; | 452 StreamParams stream_param; |
467 stream_param.id = stream_it->id; | 453 stream_param.id = sender.track_id; |
468 // Add the generated ssrc. | 454 // Add the generated ssrc. |
469 for (size_t i = 0; i < ssrcs.size(); ++i) { | 455 for (size_t i = 0; i < ssrcs.size(); ++i) { |
470 stream_param.ssrcs.push_back(ssrcs[i]); | 456 stream_param.ssrcs.push_back(ssrcs[i]); |
471 } | 457 } |
472 if (stream_it->num_sim_layers > 1) { | 458 if (sender.num_sim_layers > 1) { |
473 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs); | 459 SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs); |
474 stream_param.ssrc_groups.push_back(group); | 460 stream_param.ssrc_groups.push_back(group); |
475 } | 461 } |
476 // Generate extra ssrcs for include_rtx_streams case. | 462 // Generate extra ssrcs for include_rtx_streams case. |
477 if (include_rtx_streams) { | 463 if (include_rtx_streams) { |
478 // Generate an RTX ssrc for every ssrc in the group. | 464 // Generate an RTX ssrc for every ssrc in the group. |
479 std::vector<uint32_t> rtx_ssrcs; | 465 std::vector<uint32_t> rtx_ssrcs; |
480 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()), | 466 GenerateSsrcs(*current_streams, static_cast<int>(ssrcs.size()), |
481 &rtx_ssrcs); | 467 &rtx_ssrcs); |
482 for (size_t i = 0; i < ssrcs.size(); ++i) { | 468 for (size_t i = 0; i < ssrcs.size(); ++i) { |
483 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]); | 469 stream_param.AddFidSsrc(ssrcs[i], rtx_ssrcs[i]); |
484 } | 470 } |
485 content_description->set_multistream(true); | 471 content_description->set_multistream(true); |
486 } | 472 } |
487 // Generate extra ssrc for include_flexfec_stream case. | 473 // Generate extra ssrc for include_flexfec_stream case. |
488 if (include_flexfec_stream) { | 474 if (include_flexfec_stream) { |
489 // TODO(brandtr): Update when we support multistream protection. | 475 // TODO(brandtr): Update when we support multistream protection. |
490 if (ssrcs.size() == 1) { | 476 if (ssrcs.size() == 1) { |
491 std::vector<uint32_t> flexfec_ssrcs; | 477 std::vector<uint32_t> flexfec_ssrcs; |
492 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs); | 478 GenerateSsrcs(*current_streams, 1, &flexfec_ssrcs); |
493 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]); | 479 stream_param.AddFecFrSsrc(ssrcs[0], flexfec_ssrcs[0]); |
494 content_description->set_multistream(true); | 480 content_description->set_multistream(true); |
495 } else if (!ssrcs.empty()) { | 481 } else if (!ssrcs.empty()) { |
496 LOG(LS_WARNING) | 482 LOG(LS_WARNING) |
497 << "Our FlexFEC implementation only supports protecting " | 483 << "Our FlexFEC implementation only supports protecting " |
498 << "a single media streams. This session has multiple " | 484 << "a single media streams. This session has multiple " |
499 << "media streams however, so no FlexFEC SSRC will be generated."; | 485 << "media streams however, so no FlexFEC SSRC will be generated."; |
500 } | 486 } |
501 } | 487 } |
502 stream_param.cname = options.rtcp_cname; | 488 stream_param.cname = rtcp_cname; |
503 stream_param.sync_label = stream_it->sync_label; | 489 stream_param.sync_label = sender.stream_id; |
504 content_description->AddStream(stream_param); | 490 content_description->AddStream(stream_param); |
505 | 491 |
506 // Store the new StreamParams in current_streams. | 492 // Store the new StreamParams in current_streams. |
507 // This is necessary so that we can use the CNAME for other media types. | 493 // This is necessary so that we can use the CNAME for other media types. |
508 current_streams->push_back(stream_param); | 494 current_streams->push_back(stream_param); |
509 } else { | 495 } else { |
510 content_description->AddStream(*param); | 496 content_description->AddStream(*param); |
511 } | 497 } |
512 } | 498 } |
513 return true; | 499 return true; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
711 } | 697 } |
712 } | 698 } |
713 return false; | 699 return false; |
714 } | 700 } |
715 | 701 |
716 template <class C> | 702 template <class C> |
717 static bool IsFlexfecCodec(const C& codec) { | 703 static bool IsFlexfecCodec(const C& codec) { |
718 return stricmp(codec.name.c_str(), kFlexfecCodecName) == 0; | 704 return stricmp(codec.name.c_str(), kFlexfecCodecName) == 0; |
719 } | 705 } |
720 | 706 |
721 static TransportOptions GetTransportOptions(const MediaSessionOptions& options, | 707 // Create a media content to be offered in a session-initiate for the |
722 const std::string& content_name) { | 708 // given |sender_options|, according to the given options.rtcp_mux, |
723 TransportOptions transport_options; | 709 // session_options.is_muc, |
724 auto it = options.transport_options.find(content_name); | 710 // codecs, secure_transport, crypto, and current_streams. If we don't |
725 if (it != options.transport_options.end()) { | |
726 transport_options = it->second; | |
727 } | |
728 transport_options.enable_ice_renomination = options.enable_ice_renomination; | |
729 return transport_options; | |
730 } | |
731 | |
732 // Create a media content to be offered in a session-initiate, | |
733 // according to the given options.rtcp_mux, options.is_muc, | |
734 // options.streams, codecs, secure_transport, crypto, and streams. If we don't | |
735 // currently have crypto (in current_cryptos) and it is enabled (in | 711 // currently have crypto (in current_cryptos) and it is enabled (in |
736 // secure_policy), crypto is created (according to crypto_suites). If | 712 // secure_policy), crypto is created (according to crypto_suites). The created |
737 // add_legacy_stream is true, and current_streams is empty, a legacy | 713 // content is added to the offer. |
738 // stream is created. The created content is added to the offer. | |
739 template <class C> | 714 template <class C> |
740 static bool CreateMediaContentOffer( | 715 static bool CreateMediaContentOffer( |
741 const MediaSessionOptions& options, | 716 const std::vector<SenderOptions>& sender_options, |
| 717 const MediaSessionOptions& session_options, |
742 const std::vector<C>& codecs, | 718 const std::vector<C>& codecs, |
743 const SecurePolicy& secure_policy, | 719 const SecurePolicy& secure_policy, |
744 const CryptoParamsVec* current_cryptos, | 720 const CryptoParamsVec* current_cryptos, |
745 const std::vector<std::string>& crypto_suites, | 721 const std::vector<std::string>& crypto_suites, |
746 const RtpHeaderExtensions& rtp_extensions, | 722 const RtpHeaderExtensions& rtp_extensions, |
747 bool add_legacy_stream, | |
748 StreamParamsVec* current_streams, | 723 StreamParamsVec* current_streams, |
749 MediaContentDescriptionImpl<C>* offer) { | 724 MediaContentDescriptionImpl<C>* offer) { |
750 offer->AddCodecs(codecs); | 725 offer->AddCodecs(codecs); |
751 | 726 |
752 offer->set_rtcp_mux(options.rtcp_mux_enabled); | 727 offer->set_rtcp_mux(session_options.rtcp_mux_enabled); |
753 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) { | 728 if (offer->type() == cricket::MEDIA_TYPE_VIDEO) { |
754 offer->set_rtcp_reduced_size(true); | 729 offer->set_rtcp_reduced_size(true); |
755 } | 730 } |
756 offer->set_multistream(options.is_muc); | 731 offer->set_multistream(session_options.is_muc); |
757 offer->set_rtp_header_extensions(rtp_extensions); | 732 offer->set_rtp_header_extensions(rtp_extensions); |
758 | 733 |
759 if (!AddStreamParams(offer->type(), options, current_streams, offer, | 734 if (!AddStreamParams(sender_options, session_options.rtcp_cname, |
760 add_legacy_stream)) { | 735 current_streams, offer)) { |
761 return false; | 736 return false; |
762 } | 737 } |
763 | 738 |
764 #ifdef HAVE_SRTP | 739 #ifdef HAVE_SRTP |
765 if (secure_policy != SEC_DISABLED) { | 740 if (secure_policy != SEC_DISABLED) { |
766 if (current_cryptos) { | 741 if (current_cryptos) { |
767 AddMediaCryptos(*current_cryptos, offer); | 742 AddMediaCryptos(*current_cryptos, offer); |
768 } | 743 } |
769 if (offer->cryptos().empty()) { | 744 if (offer->cryptos().empty()) { |
770 if (!CreateMediaCryptos(crypto_suites, offer)) { | 745 if (!CreateMediaCryptos(crypto_suites, offer)) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 } | 835 } |
861 if (found_codec) { | 836 if (found_codec) { |
862 *found_codec = potential_match; | 837 *found_codec = potential_match; |
863 } | 838 } |
864 return true; | 839 return true; |
865 } | 840 } |
866 } | 841 } |
867 return false; | 842 return false; |
868 } | 843 } |
869 | 844 |
870 // Adds all codecs from |reference_codecs| to |offered_codecs| that dont' | 845 // Find the codec in |codec_list| that |rtx_codec| is associated with. |
| 846 template <class C> |
| 847 static const C* GetAssociatedCodec(const std::vector<C>& codec_list, |
| 848 const C& rtx_codec) { |
| 849 std::string associated_pt_str; |
| 850 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType, |
| 851 &associated_pt_str)) { |
| 852 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name |
| 853 << " is missing an associated payload type."; |
| 854 return nullptr; |
| 855 } |
| 856 |
| 857 int associated_pt; |
| 858 if (!rtc::FromString(associated_pt_str, &associated_pt)) { |
| 859 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str |
| 860 << " of RTX codec " << rtx_codec.name << " to an integer."; |
| 861 return nullptr; |
| 862 } |
| 863 |
| 864 // Find the associated reference codec for the reference RTX codec. |
| 865 const C* associated_codec = FindCodecById(codec_list, associated_pt); |
| 866 if (!associated_codec) { |
| 867 LOG(LS_WARNING) << "Couldn't find associated codec with payload type " |
| 868 << associated_pt << " for RTX codec " << rtx_codec.name |
| 869 << "."; |
| 870 } |
| 871 return associated_codec; |
| 872 } |
| 873 |
| 874 // Adds all codecs from |reference_codecs| to |offered_codecs| that don't |
871 // already exist in |offered_codecs| and ensure the payload types don't | 875 // already exist in |offered_codecs| and ensure the payload types don't |
872 // collide. | 876 // collide. If |can_modify_codecs| is false, a codec is only added if it |
| 877 // can be added without changing any parameters (namely payload type, |
| 878 // associated payload type). |
873 template <class C> | 879 template <class C> |
874 static void FindCodecsToOffer( | 880 static void MergeCodecs(const std::vector<C>& reference_codecs, |
875 const std::vector<C>& reference_codecs, | 881 bool can_modify_codecs, |
876 std::vector<C>* offered_codecs, | 882 std::vector<C>* offered_codecs, |
877 UsedPayloadTypes* used_pltypes) { | 883 UsedPayloadTypes* used_pltypes) { |
878 | |
879 // Add all new codecs that are not RTX codecs. | 884 // Add all new codecs that are not RTX codecs. |
880 for (const C& reference_codec : reference_codecs) { | 885 for (const C& reference_codec : reference_codecs) { |
881 if (!IsRtxCodec(reference_codec) && | 886 if (!IsRtxCodec(reference_codec) && |
882 !FindMatchingCodec<C>(reference_codecs, *offered_codecs, | 887 !FindMatchingCodec<C>(reference_codecs, *offered_codecs, |
883 reference_codec, nullptr)) { | 888 reference_codec, nullptr)) { |
884 C codec = reference_codec; | 889 C codec = reference_codec; |
885 used_pltypes->FindAndSetIdUsed(&codec); | 890 if (used_pltypes->FindAndSetIdUsed(&codec, can_modify_codecs)) { |
886 offered_codecs->push_back(codec); | 891 offered_codecs->push_back(codec); |
| 892 } |
887 } | 893 } |
888 } | 894 } |
889 | 895 |
890 // Add all new RTX codecs. | 896 // Add all new RTX codecs. |
891 for (const C& reference_codec : reference_codecs) { | 897 for (const C& reference_codec : reference_codecs) { |
892 if (IsRtxCodec(reference_codec) && | 898 if (IsRtxCodec(reference_codec) && |
893 !FindMatchingCodec<C>(reference_codecs, *offered_codecs, | 899 !FindMatchingCodec<C>(reference_codecs, *offered_codecs, |
894 reference_codec, nullptr)) { | 900 reference_codec, nullptr)) { |
895 C rtx_codec = reference_codec; | 901 C rtx_codec = reference_codec; |
896 | 902 const C* associated_codec = |
897 std::string associated_pt_str; | 903 GetAssociatedCodec(reference_codecs, rtx_codec); |
898 if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType, | 904 if (!associated_codec) { |
899 &associated_pt_str)) { | |
900 LOG(LS_WARNING) << "RTX codec " << rtx_codec.name | |
901 << " is missing an associated payload type."; | |
902 continue; | 905 continue; |
903 } | 906 } |
904 | 907 |
905 int associated_pt; | |
906 if (!rtc::FromString(associated_pt_str, &associated_pt)) { | |
907 LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str | |
908 << " of RTX codec " << rtx_codec.name | |
909 << " to an integer."; | |
910 continue; | |
911 } | |
912 | |
913 // Find the associated reference codec for the reference RTX codec. | |
914 const C* associated_codec = | |
915 FindCodecById(reference_codecs, associated_pt); | |
916 if (!associated_codec) { | |
917 LOG(LS_WARNING) << "Couldn't find associated codec with payload type " | |
918 << associated_pt << " for RTX codec " << rtx_codec.name | |
919 << "."; | |
920 continue; | |
921 } | |
922 | |
923 // Find a codec in the offered list that matches the reference codec. | 908 // Find a codec in the offered list that matches the reference codec. |
924 // Its payload type may be different than the reference codec. | 909 // Its payload type may be different than the reference codec. |
925 C matching_codec; | 910 C matching_codec; |
926 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs, | 911 if (!FindMatchingCodec<C>(reference_codecs, *offered_codecs, |
927 *associated_codec, &matching_codec)) { | 912 *associated_codec, &matching_codec)) { |
928 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name | 913 LOG(LS_WARNING) << "Couldn't find matching " << associated_codec->name |
929 << " codec."; | 914 << " codec."; |
930 continue; | 915 continue; |
931 } | 916 } |
932 | 917 |
| 918 if (!can_modify_codecs && matching_codec.id != associated_codec->id) { |
| 919 continue; |
| 920 } |
| 921 |
933 rtx_codec.params[kCodecParamAssociatedPayloadType] = | 922 rtx_codec.params[kCodecParamAssociatedPayloadType] = |
934 rtc::ToString(matching_codec.id); | 923 rtc::ToString(matching_codec.id); |
935 used_pltypes->FindAndSetIdUsed(&rtx_codec); | 924 if (used_pltypes->FindAndSetIdUsed(&rtx_codec, can_modify_codecs)) { |
936 offered_codecs->push_back(rtx_codec); | 925 offered_codecs->push_back(rtx_codec); |
| 926 } |
937 } | 927 } |
938 } | 928 } |
939 } | 929 } |
940 | 930 |
941 static bool FindByUri(const RtpHeaderExtensions& extensions, | 931 static bool FindByUri(const RtpHeaderExtensions& extensions, |
942 const webrtc::RtpExtension& ext_to_match, | 932 const webrtc::RtpExtension& ext_to_match, |
943 webrtc::RtpExtension* found_extension) { | 933 webrtc::RtpExtension* found_extension) { |
944 for (RtpHeaderExtensions::const_iterator it = extensions.begin(); | 934 for (RtpHeaderExtensions::const_iterator it = extensions.begin(); |
945 it != extensions.end(); ++it) { | 935 it != extensions.end(); ++it) { |
946 // We assume that all URIs are given in a canonical format. | 936 // We assume that all URIs are given in a canonical format. |
947 if (it->uri == ext_to_match.uri) { | 937 if (it->uri == ext_to_match.uri) { |
948 if (found_extension != NULL) { | 938 if (found_extension != NULL) { |
949 *found_extension = *it; | 939 *found_extension = *it; |
950 } | 940 } |
951 return true; | 941 return true; |
952 } | 942 } |
953 } | 943 } |
954 return false; | 944 return false; |
955 } | 945 } |
956 | 946 |
957 // Iterates through |offered_extensions|, adding each one to |all_extensions| | 947 // Adds all extensions from |reference_extensions| to |offered_extensions| that |
958 // and |used_ids|, and resolving ID conflicts. If an offered extension has the | 948 // don't already exist in |offered_extensions| and ensure the IDs don't |
959 // same URI as one in |all_extensions|, it will re-use the same ID and won't be | 949 // collide. If an extension is added, it's also added to |all_extensions|, and |
960 // treated as a conflict. | 950 // if the extension is in |all_extensions| its ID is used. If |
961 static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions, | 951 // |can_modify_extensions| is false, a extension is only added if it can be |
962 RtpHeaderExtensions* all_extensions, | 952 // added without changing the ID. |
963 UsedRtpHeaderExtensionIds* used_ids) { | 953 static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions, |
964 for (auto& extension : *offered_extensions) { | 954 bool can_modify_extension, |
965 webrtc::RtpExtension existing; | 955 RtpHeaderExtensions* offered_extensions, |
966 if (FindByUri(*all_extensions, extension, &existing)) { | 956 RtpHeaderExtensions* all_extensions, |
967 extension.id = existing.id; | 957 UsedRtpHeaderExtensionIds* used_ids) { |
968 } else { | |
969 used_ids->FindAndSetIdUsed(&extension); | |
970 all_extensions->push_back(extension); | |
971 } | |
972 } | |
973 } | |
974 | |
975 // Adds |reference_extensions| to |offered_extensions|, while updating | |
976 // |all_extensions| and |used_ids|. | |
977 static void FindRtpHdrExtsToOffer( | |
978 const RtpHeaderExtensions& reference_extensions, | |
979 RtpHeaderExtensions* offered_extensions, | |
980 RtpHeaderExtensions* all_extensions, | |
981 UsedRtpHeaderExtensionIds* used_ids) { | |
982 for (auto reference_extension : reference_extensions) { | 958 for (auto reference_extension : reference_extensions) { |
983 if (!FindByUri(*offered_extensions, reference_extension, NULL)) { | 959 if (!FindByUri(*offered_extensions, reference_extension, NULL)) { |
984 webrtc::RtpExtension existing; | 960 webrtc::RtpExtension existing; |
985 if (FindByUri(*all_extensions, reference_extension, &existing)) { | 961 if (FindByUri(*all_extensions, reference_extension, &existing)) { |
986 offered_extensions->push_back(existing); | 962 offered_extensions->push_back(existing); |
987 } else { | 963 } else { |
988 used_ids->FindAndSetIdUsed(&reference_extension); | 964 webrtc::RtpExtension extension = reference_extension; |
989 all_extensions->push_back(reference_extension); | 965 if (used_ids->FindAndSetIdUsed(&extension, can_modify_extension)) { |
990 offered_extensions->push_back(reference_extension); | 966 all_extensions->push_back(extension); |
| 967 offered_extensions->push_back(extension); |
| 968 } |
991 } | 969 } |
992 } | 970 } |
993 } | 971 } |
994 } | 972 } |
995 | 973 |
996 static void NegotiateRtpHeaderExtensions( | 974 static void NegotiateRtpHeaderExtensions( |
997 const RtpHeaderExtensions& local_extensions, | 975 const RtpHeaderExtensions& local_extensions, |
998 const RtpHeaderExtensions& offered_extensions, | 976 const RtpHeaderExtensions& offered_extensions, |
999 RtpHeaderExtensions* negotiated_extenstions) { | 977 RtpHeaderExtensions* negotiated_extenstions) { |
1000 RtpHeaderExtensions::const_iterator ours; | 978 RtpHeaderExtensions::const_iterator ours; |
(...skipping 11 matching lines...) Expand all Loading... |
1012 AudioCodecs::iterator iter = audio_codecs->begin(); | 990 AudioCodecs::iterator iter = audio_codecs->begin(); |
1013 while (iter != audio_codecs->end()) { | 991 while (iter != audio_codecs->end()) { |
1014 if (stricmp(iter->name.c_str(), kComfortNoiseCodecName) == 0) { | 992 if (stricmp(iter->name.c_str(), kComfortNoiseCodecName) == 0) { |
1015 iter = audio_codecs->erase(iter); | 993 iter = audio_codecs->erase(iter); |
1016 } else { | 994 } else { |
1017 ++iter; | 995 ++iter; |
1018 } | 996 } |
1019 } | 997 } |
1020 } | 998 } |
1021 | 999 |
1022 // Create a media content to be answered in a session-accept, | 1000 // Create a media content to be answered in a session-accept for |
1023 // according to the given options.rtcp_mux, options.streams, codecs, | 1001 // the given |sender_options|, according to the given session_options.rtcp_mux, |
1024 // crypto, and streams. If we don't currently have crypto (in | 1002 // session_options.streams, codecs, crypto, and current_streams. If we don't |
1025 // current_cryptos) and it is enabled (in secure_policy), crypto is | 1003 // currently |
1026 // created (according to crypto_suites). If add_legacy_stream is | 1004 // have crypto (in current_cryptos) and it is enabled (in secure_policy), |
1027 // true, and current_streams is empty, a legacy stream is created. | 1005 // crypto is created (according to crypto_suites). The codecs, rtcp_mux, and |
1028 // The codecs, rtcp_mux, and crypto are all negotiated with the offer | 1006 // crypto are all negotiated with the offer from the incoming session-initiate. |
1029 // from the incoming session-initiate. If the negotiation fails, this | 1007 // If the negotiation fails, this method returns false. The created content is |
1030 // method returns false. The created content is added to the offer. | 1008 // added to the offer. |
1031 template <class C> | 1009 template <class C> |
1032 static bool CreateMediaContentAnswer( | 1010 static bool CreateMediaContentAnswer( |
1033 const MediaContentDescriptionImpl<C>* offer, | 1011 const MediaContentDescriptionImpl<C>* offer, |
1034 const MediaSessionOptions& options, | 1012 const std::vector<SenderOptions>& sender_options, |
| 1013 // TODO: combine these two params into mediadescriptionoptions |
| 1014 RtpTransceiverDirection desired_direction, |
| 1015 const MediaSessionOptions& session_options, |
1035 const std::vector<C>& local_codecs, | 1016 const std::vector<C>& local_codecs, |
1036 const SecurePolicy& sdes_policy, | 1017 const SecurePolicy& sdes_policy, |
1037 const CryptoParamsVec* current_cryptos, | 1018 const CryptoParamsVec* current_cryptos, |
1038 const RtpHeaderExtensions& local_rtp_extenstions, | 1019 const RtpHeaderExtensions& local_rtp_extenstions, |
1039 StreamParamsVec* current_streams, | 1020 StreamParamsVec* current_streams, |
1040 bool add_legacy_stream, | |
1041 bool bundle_enabled, | 1021 bool bundle_enabled, |
1042 MediaContentDescriptionImpl<C>* answer) { | 1022 MediaContentDescriptionImpl<C>* answer) { |
1043 std::vector<C> negotiated_codecs; | 1023 std::vector<C> negotiated_codecs; |
1044 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs); | 1024 NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs); |
1045 answer->AddCodecs(negotiated_codecs); | 1025 answer->AddCodecs(negotiated_codecs); |
1046 answer->set_protocol(offer->protocol()); | 1026 answer->set_protocol(offer->protocol()); |
1047 RtpHeaderExtensions negotiated_rtp_extensions; | 1027 RtpHeaderExtensions negotiated_rtp_extensions; |
1048 NegotiateRtpHeaderExtensions(local_rtp_extenstions, | 1028 NegotiateRtpHeaderExtensions(local_rtp_extenstions, |
1049 offer->rtp_header_extensions(), | 1029 offer->rtp_header_extensions(), |
1050 &negotiated_rtp_extensions); | 1030 &negotiated_rtp_extensions); |
1051 answer->set_rtp_header_extensions(negotiated_rtp_extensions); | 1031 answer->set_rtp_header_extensions(negotiated_rtp_extensions); |
1052 | 1032 |
1053 answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux()); | 1033 answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux()); |
1054 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) { | 1034 if (answer->type() == cricket::MEDIA_TYPE_VIDEO) { |
1055 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size()); | 1035 answer->set_rtcp_reduced_size(offer->rtcp_reduced_size()); |
1056 } | 1036 } |
1057 | 1037 |
1058 if (sdes_policy != SEC_DISABLED) { | 1038 if (sdes_policy != SEC_DISABLED) { |
1059 CryptoParams crypto; | 1039 CryptoParams crypto; |
1060 if (SelectCrypto(offer, bundle_enabled, options.crypto_options, &crypto)) { | 1040 if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options, |
| 1041 &crypto)) { |
1061 if (current_cryptos) { | 1042 if (current_cryptos) { |
1062 FindMatchingCrypto(*current_cryptos, crypto, &crypto); | 1043 FindMatchingCrypto(*current_cryptos, crypto, &crypto); |
1063 } | 1044 } |
1064 answer->AddCrypto(crypto); | 1045 answer->AddCrypto(crypto); |
1065 } | 1046 } |
1066 } | 1047 } |
1067 | 1048 |
1068 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) { | 1049 if (answer->cryptos().empty() && sdes_policy == SEC_REQUIRED) { |
1069 return false; | 1050 return false; |
1070 } | 1051 } |
1071 | 1052 |
1072 if (!AddStreamParams(answer->type(), options, current_streams, answer, | 1053 if (!AddStreamParams(sender_options, session_options.rtcp_cname, |
1073 add_legacy_stream)) { | 1054 current_streams, answer)) { |
1074 return false; // Something went seriously wrong. | 1055 return false; // Something went seriously wrong. |
1075 } | 1056 } |
1076 | 1057 |
1077 // Make sure the answer media content direction is per default set as | |
1078 // described in RFC3264 section 6.1. | |
1079 const bool is_data = !IsRtpProtocol(answer->protocol()); | |
1080 const bool has_send_streams = !answer->streams().empty(); | |
1081 const bool wants_send = has_send_streams || is_data; | |
1082 const bool recv_audio = | |
1083 answer->type() == cricket::MEDIA_TYPE_AUDIO && options.recv_audio; | |
1084 const bool recv_video = | |
1085 answer->type() == cricket::MEDIA_TYPE_VIDEO && options.recv_video; | |
1086 const bool recv_data = | |
1087 answer->type() == cricket::MEDIA_TYPE_DATA; | |
1088 const bool wants_receive = recv_audio || recv_video || recv_data; | |
1089 | |
1090 auto offer_rtd = | 1058 auto offer_rtd = |
1091 RtpTransceiverDirection::FromMediaContentDirection(offer->direction()); | 1059 RtpTransceiverDirection::FromMediaContentDirection(offer->direction()); |
1092 auto wants_rtd = RtpTransceiverDirection(wants_send, wants_receive); | 1060 answer->set_direction( |
1093 answer->set_direction(NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd) | 1061 NegotiateRtpTransceiverDirection(offer_rtd, desired_direction) |
1094 .ToMediaContentDirection()); | 1062 .ToMediaContentDirection()); |
1095 return true; | 1063 return true; |
1096 } | 1064 } |
1097 | 1065 |
1098 static bool IsDtlsRtp(const std::string& protocol) { | 1066 static bool IsDtlsRtp(const std::string& protocol) { |
1099 // Most-likely values first. | 1067 // Most-likely values first. |
1100 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" || | 1068 return protocol == "UDP/TLS/RTP/SAVPF" || protocol == "TCP/TLS/RTP/SAVPF" || |
1101 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP"; | 1069 protocol == "UDP/TLS/RTP/SAVP" || protocol == "TCP/TLS/RTP/SAVP"; |
1102 } | 1070 } |
1103 | 1071 |
1104 static bool IsPlainRtp(const std::string& protocol) { | 1072 static bool IsPlainRtp(const std::string& protocol) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 const TransportInfo* info = | 1134 const TransportInfo* info = |
1167 current_description->GetTransportInfoByName(content_name); | 1135 current_description->GetTransportInfoByName(content_name); |
1168 if (info) { | 1136 if (info) { |
1169 desc = &info->description; | 1137 desc = &info->description; |
1170 } | 1138 } |
1171 } | 1139 } |
1172 return desc; | 1140 return desc; |
1173 } | 1141 } |
1174 | 1142 |
1175 // Gets the current DTLS state from the transport description. | 1143 // Gets the current DTLS state from the transport description. |
1176 static bool IsDtlsActive( | 1144 static bool IsDtlsActive(const ContentInfo* content, |
1177 const std::string& content_name, | 1145 const SessionDescription* current_description) { |
1178 const SessionDescription* current_description) { | 1146 if (!content) { |
1179 if (!current_description) | |
1180 return false; | 1147 return false; |
1181 | 1148 } |
1182 const ContentInfo* content = | |
1183 current_description->GetContentByName(content_name); | |
1184 if (!content) | |
1185 return false; | |
1186 | 1149 |
1187 const TransportDescription* current_tdesc = | 1150 const TransportDescription* current_tdesc = |
1188 GetTransportDescription(content_name, current_description); | 1151 GetTransportDescription(content->name, current_description); |
1189 if (!current_tdesc) | 1152 if (!current_tdesc) { |
1190 return false; | 1153 return false; |
| 1154 } |
1191 | 1155 |
1192 return current_tdesc->secure(); | 1156 return current_tdesc->secure(); |
1193 } | 1157 } |
1194 | 1158 |
1195 std::string MediaTypeToString(MediaType type) { | 1159 std::string MediaTypeToString(MediaType type) { |
1196 std::string type_str; | 1160 std::string type_str; |
1197 switch (type) { | 1161 switch (type) { |
1198 case MEDIA_TYPE_AUDIO: | 1162 case MEDIA_TYPE_AUDIO: |
1199 type_str = "audio"; | 1163 type_str = "audio"; |
1200 break; | 1164 break; |
(...skipping 26 matching lines...) Expand all Loading... |
1227 dir_str = "sendrecv"; | 1191 dir_str = "sendrecv"; |
1228 break; | 1192 break; |
1229 default: | 1193 default: |
1230 ASSERT(false); | 1194 ASSERT(false); |
1231 break; | 1195 break; |
1232 } | 1196 } |
1233 | 1197 |
1234 return dir_str; | 1198 return dir_str; |
1235 } | 1199 } |
1236 | 1200 |
1237 void MediaSessionOptions::AddSendStream(MediaType type, | 1201 void MediaDescriptionOptions::AddAudioSender(const std::string& track_id, |
1238 const std::string& id, | 1202 const std::string& stream_id) { |
1239 const std::string& sync_label) { | 1203 RTC_DCHECK(type == MEDIA_TYPE_AUDIO); |
1240 AddSendStreamInternal(type, id, sync_label, 1); | 1204 AddSenderInternal(track_id, stream_id, 1); |
1241 } | 1205 } |
1242 | 1206 |
1243 void MediaSessionOptions::AddSendVideoStream( | 1207 void MediaDescriptionOptions::AddVideoSender(const std::string& track_id, |
1244 const std::string& id, | 1208 const std::string& stream_id, |
1245 const std::string& sync_label, | 1209 int num_sim_layers) { |
1246 int num_sim_layers) { | 1210 RTC_DCHECK(type == MEDIA_TYPE_VIDEO); |
1247 AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers); | 1211 AddSenderInternal(track_id, stream_id, num_sim_layers); |
1248 } | 1212 } |
1249 | 1213 |
1250 void MediaSessionOptions::AddSendStreamInternal( | 1214 void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id, |
1251 MediaType type, | 1215 const std::string& stream_id) { |
1252 const std::string& id, | 1216 RTC_DCHECK(type == MEDIA_TYPE_DATA); |
1253 const std::string& sync_label, | 1217 AddSenderInternal(track_id, stream_id, 1); |
1254 int num_sim_layers) { | |
1255 streams.push_back(Stream(type, id, sync_label, num_sim_layers)); | |
1256 | |
1257 // If we haven't already set the data_channel_type, and we add a | |
1258 // stream, we assume it's an RTP data stream. | |
1259 if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE) | |
1260 data_channel_type = DCT_RTP; | |
1261 } | 1218 } |
1262 | 1219 |
1263 void MediaSessionOptions::RemoveSendStream(MediaType type, | 1220 void MediaDescriptionOptions::AddSenderInternal(const std::string& track_id, |
1264 const std::string& id) { | 1221 const std::string& stream_id, |
1265 Streams::iterator stream_it = streams.begin(); | 1222 int num_sim_layers) { |
1266 for (; stream_it != streams.end(); ++stream_it) { | 1223 sender_options.push_back(SenderOptions{track_id, stream_id, num_sim_layers}); |
1267 if (stream_it->type == type && stream_it->id == id) { | |
1268 streams.erase(stream_it); | |
1269 return; | |
1270 } | |
1271 } | |
1272 ASSERT(false); | |
1273 } | 1224 } |
1274 | 1225 |
1275 bool MediaSessionOptions::HasSendMediaStream(MediaType type) const { | 1226 bool MediaSessionOptions::HasMediaDescription(MediaType type) const { |
1276 Streams::const_iterator stream_it = streams.begin(); | 1227 return std::find_if(media_description_options.begin(), |
1277 for (; stream_it != streams.end(); ++stream_it) { | 1228 media_description_options.end(), |
1278 if (stream_it->type == type) { | 1229 [type](const MediaDescriptionOptions& t) { |
1279 return true; | 1230 return t.type == type; |
1280 } | 1231 }) != media_description_options.end(); |
1281 } | 1232 } |
1282 return false; | 1233 |
| 1234 std::vector<MediaDescriptionOptions>::iterator |
| 1235 MediaSessionOptions::FindMediaDescription(const std::string& mid) { |
| 1236 return std::find_if( |
| 1237 media_description_options.begin(), media_description_options.end(), |
| 1238 [mid](const MediaDescriptionOptions& t) { return t.mid == mid; }); |
1283 } | 1239 } |
1284 | 1240 |
1285 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( | 1241 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( |
1286 const TransportDescriptionFactory* transport_desc_factory) | 1242 const TransportDescriptionFactory* transport_desc_factory) |
1287 : secure_(SEC_DISABLED), | 1243 : transport_desc_factory_(transport_desc_factory) {} |
1288 add_legacy_(true), | |
1289 transport_desc_factory_(transport_desc_factory) { | |
1290 } | |
1291 | 1244 |
1292 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( | 1245 MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( |
1293 ChannelManager* channel_manager, | 1246 ChannelManager* channel_manager, |
1294 const TransportDescriptionFactory* transport_desc_factory) | 1247 const TransportDescriptionFactory* transport_desc_factory) |
1295 : secure_(SEC_DISABLED), | 1248 : transport_desc_factory_(transport_desc_factory) { |
1296 add_legacy_(true), | |
1297 transport_desc_factory_(transport_desc_factory) { | |
1298 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_); | 1249 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_); |
1299 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_); | 1250 channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_); |
1300 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_); | 1251 channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_); |
1301 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_); | 1252 channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_); |
1302 channel_manager->GetSupportedVideoCodecs(&video_codecs_); | 1253 channel_manager->GetSupportedVideoCodecs(&video_codecs_); |
1303 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_); | 1254 channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_); |
1304 channel_manager->GetSupportedDataCodecs(&data_codecs_); | 1255 channel_manager->GetSupportedDataCodecs(&data_codecs_); |
1305 NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_, | 1256 // Precompute the intersection and union of audio send/recv codecs. |
1306 &audio_sendrecv_codecs_); | 1257 for (const AudioCodec& recv : audio_recv_codecs_) { |
| 1258 all_audio_codecs_.push_back(recv); |
| 1259 if (FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_, |
| 1260 recv, nullptr)) { |
| 1261 audio_sendrecv_codecs_.push_back(recv); |
| 1262 } |
| 1263 } |
| 1264 for (const AudioCodec& send : audio_send_codecs_) { |
| 1265 if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_, |
| 1266 send, nullptr)) { |
| 1267 // It doesn't make sense to have an RTX codec we support sending but not |
| 1268 // receiving. |
| 1269 RTC_DCHECK(!IsRtxCodec(send)); |
| 1270 all_audio_codecs_.push_back(send); |
| 1271 } |
| 1272 } |
1307 } | 1273 } |
1308 | 1274 |
1309 const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs() | 1275 const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs() |
1310 const { | 1276 const { |
1311 return audio_sendrecv_codecs_; | 1277 return audio_sendrecv_codecs_; |
1312 } | 1278 } |
1313 | 1279 |
1314 const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const { | 1280 const AudioCodecs& MediaSessionDescriptionFactory::audio_send_codecs() const { |
1315 return audio_send_codecs_; | 1281 return audio_send_codecs_; |
1316 } | 1282 } |
1317 | 1283 |
1318 const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const { | 1284 const AudioCodecs& MediaSessionDescriptionFactory::audio_recv_codecs() const { |
1319 return audio_recv_codecs_; | 1285 return audio_recv_codecs_; |
1320 } | 1286 } |
1321 | 1287 |
1322 void MediaSessionDescriptionFactory::set_audio_codecs( | 1288 void MediaSessionDescriptionFactory::set_audio_codecs( |
1323 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) { | 1289 const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) { |
1324 audio_send_codecs_ = send_codecs; | 1290 audio_send_codecs_ = send_codecs; |
1325 audio_recv_codecs_ = recv_codecs; | 1291 audio_recv_codecs_ = recv_codecs; |
1326 audio_sendrecv_codecs_.clear(); | 1292 audio_sendrecv_codecs_.clear(); |
1327 // Use NegotiateCodecs to merge our codec lists, since the operation is | 1293 // Use NegotiateCodecs to merge our codec lists, since the operation is |
1328 // essentially the same. Put send_codecs as the offered_codecs, which is the | 1294 // essentially the same. Put send_codecs as the offered_codecs, which is the |
1329 // order we'd like to follow. The reasoning is that encoding is usually more | 1295 // order we'd like to follow. The reasoning is that encoding is usually more |
1330 // expensive than decoding, and prioritizing a codec in the send list probably | 1296 // expensive than decoding, and prioritizing a codec in the send list probably |
1331 // means it's a codec we can handle efficiently. | 1297 // means it's a codec we can handle efficiently. |
1332 NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_); | 1298 NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_); |
1333 } | 1299 } |
1334 | 1300 |
1335 SessionDescription* MediaSessionDescriptionFactory::CreateOffer( | 1301 SessionDescription* MediaSessionDescriptionFactory::CreateOffer( |
1336 const MediaSessionOptions& options, | 1302 const MediaSessionOptions& session_options, |
1337 const SessionDescription* current_description) const { | 1303 const SessionDescription* current_description) const { |
1338 std::unique_ptr<SessionDescription> offer(new SessionDescription()); | 1304 std::unique_ptr<SessionDescription> offer(new SessionDescription()); |
1339 | 1305 |
1340 StreamParamsVec current_streams; | 1306 StreamParamsVec current_streams; |
1341 GetCurrentStreamParams(current_description, ¤t_streams); | 1307 GetCurrentStreamParams(current_description, ¤t_streams); |
1342 | 1308 |
1343 const bool wants_send = | 1309 AudioCodecs offer_audio_codecs; |
1344 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_; | 1310 VideoCodecs offer_video_codecs; |
1345 const AudioCodecs& supported_audio_codecs = | 1311 DataCodecs offer_data_codecs; |
1346 GetAudioCodecsForOffer({wants_send, options.recv_audio}); | 1312 GetCodecsForOffer(current_description, &offer_audio_codecs, |
| 1313 &offer_video_codecs, &offer_data_codecs); |
1347 | 1314 |
1348 AudioCodecs audio_codecs; | 1315 if (!session_options.vad_enabled) { |
1349 VideoCodecs video_codecs; | |
1350 DataCodecs data_codecs; | |
1351 GetCodecsToOffer(current_description, supported_audio_codecs, | |
1352 video_codecs_, data_codecs_, | |
1353 &audio_codecs, &video_codecs, &data_codecs); | |
1354 | |
1355 if (!options.vad_enabled) { | |
1356 // If application doesn't want CN codecs in offer. | 1316 // If application doesn't want CN codecs in offer. |
1357 StripCNCodecs(&audio_codecs); | 1317 StripCNCodecs(&offer_audio_codecs); |
1358 } | 1318 } |
| 1319 FilterDataCodecs(&offer_data_codecs, |
| 1320 session_options.data_channel_type == DCT_SCTP); |
1359 | 1321 |
1360 RtpHeaderExtensions audio_rtp_extensions; | 1322 RtpHeaderExtensions audio_rtp_extensions; |
1361 RtpHeaderExtensions video_rtp_extensions; | 1323 RtpHeaderExtensions video_rtp_extensions; |
1362 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions, | 1324 GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions, |
1363 &video_rtp_extensions); | 1325 &video_rtp_extensions); |
1364 | 1326 |
1365 bool audio_added = false; | 1327 // Must have options for each existing section. |
1366 bool video_added = false; | |
1367 bool data_added = false; | |
1368 | |
1369 // Iterate through the contents of |current_description| to maintain the order | |
1370 // of the m-lines in the new offer. | |
1371 if (current_description) { | 1328 if (current_description) { |
1372 ContentInfos::const_iterator it = current_description->contents().begin(); | 1329 RTC_DCHECK(current_description->contents().size() <= |
1373 for (; it != current_description->contents().end(); ++it) { | 1330 session_options.media_description_options.size()); |
1374 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) { | 1331 } |
1375 if (!AddAudioContentForOffer(options, current_description, | 1332 // Iterate through the media description options, matching with existing |
1376 audio_rtp_extensions, audio_codecs, | 1333 // media descriptions in |current_description|. |
| 1334 int msection_index = 0; |
| 1335 for (const MediaDescriptionOptions& media_description_options : |
| 1336 session_options.media_description_options) { |
| 1337 const ContentInfo* current_content = nullptr; |
| 1338 if (current_description && |
| 1339 msection_index < |
| 1340 static_cast<int>(current_description->contents().size())) { |
| 1341 current_content = ¤t_description->contents()[msection_index]; |
| 1342 // Media types and mids must match. |
| 1343 RTC_DCHECK(IsMediaContentOfType(current_content, |
| 1344 media_description_options.type)); |
| 1345 RTC_DCHECK(media_description_options.mid == current_content->name); |
| 1346 } |
| 1347 switch (media_description_options.type) { |
| 1348 case MEDIA_TYPE_AUDIO: |
| 1349 if (!AddAudioContentForOffer(media_description_options, session_options, |
| 1350 current_content, current_description, |
| 1351 audio_rtp_extensions, offer_audio_codecs, |
1377 ¤t_streams, offer.get())) { | 1352 ¤t_streams, offer.get())) { |
1378 return NULL; | 1353 return nullptr; |
1379 } | 1354 } |
1380 audio_added = true; | 1355 break; |
1381 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) { | 1356 case MEDIA_TYPE_VIDEO: |
1382 if (!AddVideoContentForOffer(options, current_description, | 1357 if (!AddVideoContentForOffer(media_description_options, session_options, |
1383 video_rtp_extensions, video_codecs, | 1358 current_content, current_description, |
| 1359 video_rtp_extensions, offer_video_codecs, |
1384 ¤t_streams, offer.get())) { | 1360 ¤t_streams, offer.get())) { |
1385 return NULL; | 1361 return nullptr; |
1386 } | 1362 } |
1387 video_added = true; | 1363 break; |
1388 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) { | 1364 case MEDIA_TYPE_DATA: |
1389 MediaSessionOptions options_copy(options); | 1365 if (!AddDataContentForOffer(media_description_options, session_options, |
1390 if (IsSctp(static_cast<const MediaContentDescription*>( | 1366 current_content, current_description, |
1391 it->description))) { | 1367 offer_data_codecs, ¤t_streams, |
1392 options_copy.data_channel_type = DCT_SCTP; | 1368 offer.get())) { |
| 1369 return nullptr; |
1393 } | 1370 } |
1394 if (!AddDataContentForOffer(options_copy, current_description, | 1371 break; |
1395 &data_codecs, ¤t_streams, | 1372 default: |
1396 offer.get())) { | 1373 RTC_NOTREACHED(); |
1397 return NULL; | |
1398 } | |
1399 data_added = true; | |
1400 } else { | |
1401 ASSERT(false); | |
1402 } | |
1403 } | 1374 } |
1404 } | 1375 ++msection_index; |
1405 | |
1406 // Append contents that are not in |current_description|. | |
1407 if (!audio_added && options.has_audio() && | |
1408 !AddAudioContentForOffer(options, current_description, | |
1409 audio_rtp_extensions, audio_codecs, | |
1410 ¤t_streams, offer.get())) { | |
1411 return NULL; | |
1412 } | |
1413 if (!video_added && options.has_video() && | |
1414 !AddVideoContentForOffer(options, current_description, | |
1415 video_rtp_extensions, video_codecs, | |
1416 ¤t_streams, offer.get())) { | |
1417 return NULL; | |
1418 } | |
1419 if (!data_added && options.has_data() && | |
1420 !AddDataContentForOffer(options, current_description, &data_codecs, | |
1421 ¤t_streams, offer.get())) { | |
1422 return NULL; | |
1423 } | 1376 } |
1424 | 1377 |
1425 // Bundle the contents together, if we've been asked to do so, and update any | 1378 // Bundle the contents together, if we've been asked to do so, and update any |
1426 // parameters that need to be tweaked for BUNDLE. | 1379 // parameters that need to be tweaked for BUNDLE. |
1427 if (options.bundle_enabled) { | 1380 if (session_options.bundle_enabled && offer->contents().size() > 0u) { |
1428 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE); | 1381 ContentGroup offer_bundle(GROUP_TYPE_BUNDLE); |
1429 for (ContentInfos::const_iterator content = offer->contents().begin(); | 1382 for (const ContentInfo& content : offer->contents()) { |
1430 content != offer->contents().end(); ++content) { | 1383 // TODO(deadbeef): There are conditions that make bundling two media |
1431 offer_bundle.AddContentName(content->name); | 1384 // descriptions together illegal. For example, they use the same payload |
| 1385 // type to represent different codecs, or same IDs for different header |
| 1386 // extensions. We need to detect this and not try to bundle those media |
| 1387 // descriptions together. |
| 1388 offer_bundle.AddContentName(content.name); |
1432 } | 1389 } |
1433 offer->AddGroup(offer_bundle); | 1390 offer->AddGroup(offer_bundle); |
1434 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) { | 1391 if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) { |
1435 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle."; | 1392 LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle."; |
1436 return NULL; | 1393 return NULL; |
1437 } | 1394 } |
1438 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) { | 1395 if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) { |
1439 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle."; | 1396 LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle."; |
1440 return NULL; | 1397 return NULL; |
1441 } | 1398 } |
1442 } | 1399 } |
1443 | 1400 |
1444 return offer.release(); | 1401 return offer.release(); |
1445 } | 1402 } |
1446 | 1403 |
1447 SessionDescription* MediaSessionDescriptionFactory::CreateAnswer( | 1404 SessionDescription* MediaSessionDescriptionFactory::CreateAnswer( |
1448 const SessionDescription* offer, const MediaSessionOptions& options, | 1405 const SessionDescription* offer, |
| 1406 const MediaSessionOptions& session_options, |
1449 const SessionDescription* current_description) const { | 1407 const SessionDescription* current_description) const { |
| 1408 RTC_DCHECK(offer); |
1450 // The answer contains the intersection of the codecs in the offer with the | 1409 // The answer contains the intersection of the codecs in the offer with the |
1451 // codecs we support. As indicated by XEP-0167, we retain the same payload ids | 1410 // codecs we support. As indicated by XEP-0167, we retain the same payload ids |
1452 // from the offer in the answer. | 1411 // from the offer in the answer. |
1453 std::unique_ptr<SessionDescription> answer(new SessionDescription()); | 1412 std::unique_ptr<SessionDescription> answer(new SessionDescription()); |
1454 | 1413 |
1455 StreamParamsVec current_streams; | 1414 StreamParamsVec current_streams; |
1456 GetCurrentStreamParams(current_description, ¤t_streams); | 1415 GetCurrentStreamParams(current_description, ¤t_streams); |
1457 | 1416 |
1458 if (offer) { | 1417 // Get list of all possible codecs that respects existing payload type |
1459 ContentInfos::const_iterator it = offer->contents().begin(); | 1418 // mappings and uses a single payload type space. |
1460 for (; it != offer->contents().end(); ++it) { | 1419 // |
1461 if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) { | 1420 // Note that these lists may be further filtered for each m= section; this |
1462 if (!AddAudioContentForAnswer(offer, options, current_description, | 1421 // step is done just to establish the payload type mappings shared by all |
1463 ¤t_streams, answer.get())) { | 1422 // sections. |
1464 return NULL; | 1423 AudioCodecs answer_audio_codecs; |
| 1424 VideoCodecs answer_video_codecs; |
| 1425 DataCodecs answer_data_codecs; |
| 1426 GetCodecsForAnswer(current_description, offer, &answer_audio_codecs, |
| 1427 &answer_video_codecs, &answer_data_codecs); |
| 1428 |
| 1429 if (!session_options.vad_enabled) { |
| 1430 // If application doesn't want CN codecs in answer. |
| 1431 StripCNCodecs(&answer_audio_codecs); |
| 1432 } |
| 1433 FilterDataCodecs(&answer_data_codecs, |
| 1434 session_options.data_channel_type == DCT_SCTP); |
| 1435 |
| 1436 // Must have options for exactly as many sections as in the offer. |
| 1437 RTC_DCHECK(offer->contents().size() == |
| 1438 session_options.media_description_options.size()); |
| 1439 // Iterate through the media description options, matching with existing |
| 1440 // media descriptions in |current_description|. |
| 1441 int msection_index = 0; |
| 1442 for (const MediaDescriptionOptions& media_description_options : |
| 1443 session_options.media_description_options) { |
| 1444 const ContentInfo* offer_content = &offer->contents()[msection_index]; |
| 1445 // Media types and mids must match. |
| 1446 RTC_DCHECK( |
| 1447 IsMediaContentOfType(offer_content, media_description_options.type)); |
| 1448 RTC_DCHECK(media_description_options.mid == offer_content->name); |
| 1449 const ContentInfo* current_content = nullptr; |
| 1450 if (current_description && |
| 1451 msection_index < |
| 1452 static_cast<int>(current_description->contents().size())) { |
| 1453 current_content = ¤t_description->contents()[msection_index]; |
| 1454 // Media types and mids must match. |
| 1455 RTC_DCHECK(IsMediaContentOfType(current_content, |
| 1456 media_description_options.type)); |
| 1457 RTC_DCHECK(media_description_options.mid == current_content->name); |
| 1458 } |
| 1459 switch (media_description_options.type) { |
| 1460 case MEDIA_TYPE_AUDIO: |
| 1461 if (!AddAudioContentForAnswer( |
| 1462 media_description_options, session_options, offer_content, |
| 1463 offer, current_content, current_description, |
| 1464 answer_audio_codecs, ¤t_streams, answer.get())) { |
| 1465 return nullptr; |
1465 } | 1466 } |
1466 } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) { | 1467 break; |
1467 if (!AddVideoContentForAnswer(offer, options, current_description, | 1468 case MEDIA_TYPE_VIDEO: |
1468 ¤t_streams, answer.get())) { | 1469 if (!AddVideoContentForAnswer( |
1469 return NULL; | 1470 media_description_options, session_options, offer_content, |
| 1471 offer, current_content, current_description, |
| 1472 answer_video_codecs, ¤t_streams, answer.get())) { |
| 1473 return nullptr; |
1470 } | 1474 } |
1471 } else { | 1475 break; |
1472 ASSERT(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)); | 1476 case MEDIA_TYPE_DATA: |
1473 if (!AddDataContentForAnswer(offer, options, current_description, | 1477 if (!AddDataContentForAnswer(media_description_options, session_options, |
| 1478 offer_content, offer, current_content, |
| 1479 current_description, answer_data_codecs, |
1474 ¤t_streams, answer.get())) { | 1480 ¤t_streams, answer.get())) { |
1475 return NULL; | 1481 return nullptr; |
1476 } | 1482 } |
1477 } | 1483 break; |
| 1484 default: |
| 1485 RTC_NOTREACHED(); |
1478 } | 1486 } |
| 1487 ++msection_index; |
1479 } | 1488 } |
1480 | 1489 |
1481 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE | 1490 // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE |
1482 // group in the answer with the appropriate content names. | 1491 // group in the answer with the appropriate content names. |
1483 if (offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled) { | 1492 if (offer->HasGroup(GROUP_TYPE_BUNDLE) && session_options.bundle_enabled) { |
1484 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE); | 1493 const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE); |
1485 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE); | 1494 ContentGroup answer_bundle(GROUP_TYPE_BUNDLE); |
1486 for (ContentInfos::const_iterator content = answer->contents().begin(); | 1495 for (ContentInfos::const_iterator content = answer->contents().begin(); |
1487 content != answer->contents().end(); ++content) { | 1496 content != answer->contents().end(); ++content) { |
1488 if (!content->rejected && offer_bundle->HasContentName(content->name)) { | 1497 if (!content->rejected && offer_bundle->HasContentName(content->name)) { |
1489 answer_bundle.AddContentName(content->name); | 1498 answer_bundle.AddContentName(content->name); |
1490 } | 1499 } |
1491 } | 1500 } |
1492 if (answer_bundle.FirstContentName()) { | 1501 if (answer_bundle.FirstContentName()) { |
1493 answer->AddGroup(answer_bundle); | 1502 answer->AddGroup(answer_bundle); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1534 } else { | 1543 } else { |
1535 return audio_send_codecs_; | 1544 return audio_send_codecs_; |
1536 } | 1545 } |
1537 } else if (answer.send) { | 1546 } else if (answer.send) { |
1538 return audio_send_codecs_; | 1547 return audio_send_codecs_; |
1539 } else { | 1548 } else { |
1540 return audio_recv_codecs_; | 1549 return audio_recv_codecs_; |
1541 } | 1550 } |
1542 } | 1551 } |
1543 | 1552 |
1544 void MediaSessionDescriptionFactory::GetCodecsToOffer( | 1553 void MergeCodecsFromDescription(const SessionDescription* description, |
| 1554 bool can_modify_codecs, |
| 1555 AudioCodecs* audio_codecs, |
| 1556 VideoCodecs* video_codecs, |
| 1557 DataCodecs* data_codecs, |
| 1558 UsedPayloadTypes* used_pltypes) { |
| 1559 for (const ContentInfo& content : description->contents()) { |
| 1560 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) { |
| 1561 const AudioContentDescription* audio = |
| 1562 static_cast<AudioContentDescription*>(content.description); |
| 1563 MergeCodecs<AudioCodec>(audio->codecs(), can_modify_codecs, audio_codecs, |
| 1564 used_pltypes); |
| 1565 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) { |
| 1566 const VideoContentDescription* video = |
| 1567 static_cast<VideoContentDescription*>(content.description); |
| 1568 MergeCodecs<VideoCodec>(video->codecs(), can_modify_codecs, video_codecs, |
| 1569 used_pltypes); |
| 1570 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) { |
| 1571 const DataContentDescription* data = |
| 1572 static_cast<DataContentDescription*>(content.description); |
| 1573 MergeCodecs<DataCodec>(data->codecs(), can_modify_codecs, data_codecs, |
| 1574 used_pltypes); |
| 1575 } |
| 1576 } |
| 1577 } |
| 1578 |
| 1579 // Getting codecs for an offer involves these steps: |
| 1580 // |
| 1581 // 1. Construct payload type -> codec mappings for current description. |
| 1582 // 2. Add any reference codecs that weren't already present |
| 1583 // 3. For each individual media description (m= section), filter codecs based |
| 1584 // on the directional attribute (happens in another method). |
| 1585 void MediaSessionDescriptionFactory::GetCodecsForOffer( |
1545 const SessionDescription* current_description, | 1586 const SessionDescription* current_description, |
1546 const AudioCodecs& supported_audio_codecs, | |
1547 const VideoCodecs& supported_video_codecs, | |
1548 const DataCodecs& supported_data_codecs, | |
1549 AudioCodecs* audio_codecs, | 1587 AudioCodecs* audio_codecs, |
1550 VideoCodecs* video_codecs, | 1588 VideoCodecs* video_codecs, |
1551 DataCodecs* data_codecs) const { | 1589 DataCodecs* data_codecs) const { |
1552 UsedPayloadTypes used_pltypes; | 1590 UsedPayloadTypes used_pltypes; |
1553 audio_codecs->clear(); | 1591 audio_codecs->clear(); |
1554 video_codecs->clear(); | 1592 video_codecs->clear(); |
1555 data_codecs->clear(); | 1593 data_codecs->clear(); |
1556 | 1594 |
| 1595 // First - get all codecs from the current description if the media type |
| 1596 // is used. Add them to |used_pltypes| so the payload type is not reused if a |
| 1597 // new media type is added. |
| 1598 bool can_modify_codecs = false; |
| 1599 if (current_description) { |
| 1600 MergeCodecsFromDescription(current_description, can_modify_codecs, |
| 1601 audio_codecs, video_codecs, data_codecs, |
| 1602 &used_pltypes); |
| 1603 } |
| 1604 |
| 1605 // Add our codecs that are not in |current_description|. |
| 1606 // We can modify our reference codecs (payload type, associated payload type, |
| 1607 // etc.) since they're not part of a negotiated session description. |
| 1608 can_modify_codecs = true; |
| 1609 MergeCodecs<AudioCodec>(all_audio_codecs_, can_modify_codecs, audio_codecs, |
| 1610 &used_pltypes); |
| 1611 MergeCodecs<VideoCodec>(video_codecs_, can_modify_codecs, video_codecs, |
| 1612 &used_pltypes); |
| 1613 MergeCodecs<DataCodec>(data_codecs_, can_modify_codecs, data_codecs, |
| 1614 &used_pltypes); |
| 1615 } |
| 1616 |
| 1617 // Getting codecs for an answer involves these steps: |
| 1618 // |
| 1619 // 1. Construct payload type -> codec mappings for current description. |
| 1620 // 2. Add any codecs from the offer that weren't already present. |
| 1621 // 3. Add any remaining codecs that weren't already present. |
| 1622 // 4. For each individual media description (m= section), filter codecs based |
| 1623 // on the directional attribute (happens in another method). |
| 1624 void MediaSessionDescriptionFactory::GetCodecsForAnswer( |
| 1625 const SessionDescription* current_description, |
| 1626 const SessionDescription* remote_offer, |
| 1627 AudioCodecs* audio_codecs, |
| 1628 VideoCodecs* video_codecs, |
| 1629 DataCodecs* data_codecs) const { |
| 1630 UsedPayloadTypes used_pltypes; |
| 1631 audio_codecs->clear(); |
| 1632 video_codecs->clear(); |
| 1633 data_codecs->clear(); |
1557 | 1634 |
1558 // First - get all codecs from the current description if the media type | 1635 // First - get all codecs from the current description if the media type |
1559 // is used. | 1636 // is used. Add them to |used_pltypes| so the payload type is not reused if a |
1560 // Add them to |used_pltypes| so the payloadtype is not reused if a new media | 1637 // new media type is added. |
1561 // type is added. | 1638 bool can_modify_codecs = false; |
1562 if (current_description) { | 1639 if (current_description) { |
1563 const AudioContentDescription* audio = | 1640 MergeCodecsFromDescription(current_description, can_modify_codecs, |
1564 GetFirstAudioContentDescription(current_description); | 1641 audio_codecs, video_codecs, data_codecs, |
1565 if (audio) { | 1642 &used_pltypes); |
1566 *audio_codecs = audio->codecs(); | 1643 } |
1567 used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs); | 1644 |
1568 } | 1645 // First, filter out codecs that we don't support at all and should ignore. |
1569 const VideoContentDescription* video = | 1646 AudioCodecs filtered_offered_audio_codecs; |
1570 GetFirstVideoContentDescription(current_description); | 1647 VideoCodecs filtered_offered_video_codecs; |
1571 if (video) { | 1648 DataCodecs filtered_offered_data_codecs; |
1572 *video_codecs = video->codecs(); | 1649 for (const ContentInfo& content : remote_offer->contents()) { |
1573 used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs); | 1650 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) { |
1574 } | 1651 const AudioContentDescription* audio = |
1575 const DataContentDescription* data = | 1652 static_cast<AudioContentDescription*>(content.description); |
1576 GetFirstDataContentDescription(current_description); | 1653 for (const AudioCodec& offered_audio_codec : audio->codecs()) { |
1577 if (data) { | 1654 if (!FindMatchingCodec<AudioCodec>(audio->codecs(), |
1578 *data_codecs = data->codecs(); | 1655 filtered_offered_audio_codecs, |
1579 used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs); | 1656 offered_audio_codec, nullptr) && |
| 1657 FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_, |
| 1658 offered_audio_codec, nullptr)) { |
| 1659 filtered_offered_audio_codecs.push_back(offered_audio_codec); |
| 1660 } |
| 1661 } |
| 1662 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) { |
| 1663 const VideoContentDescription* video = |
| 1664 static_cast<VideoContentDescription*>(content.description); |
| 1665 for (const VideoCodec& offered_video_codec : video->codecs()) { |
| 1666 if (!FindMatchingCodec<VideoCodec>(video->codecs(), |
| 1667 filtered_offered_video_codecs, |
| 1668 offered_video_codec, nullptr) && |
| 1669 FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_, |
| 1670 offered_video_codec, nullptr)) { |
| 1671 filtered_offered_video_codecs.push_back(offered_video_codec); |
| 1672 } |
| 1673 } |
| 1674 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) { |
| 1675 const DataContentDescription* data = |
| 1676 static_cast<DataContentDescription*>(content.description); |
| 1677 for (const DataCodec& offered_data_codec : data->codecs()) { |
| 1678 if (!FindMatchingCodec<DataCodec>(data->codecs(), |
| 1679 filtered_offered_data_codecs, |
| 1680 offered_data_codec, nullptr) && |
| 1681 FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_, |
| 1682 offered_data_codec, nullptr)) { |
| 1683 filtered_offered_data_codecs.push_back(offered_data_codec); |
| 1684 } |
| 1685 } |
1580 } | 1686 } |
1581 } | 1687 } |
1582 | 1688 |
1583 // Add our codecs that are not in |current_description|. | 1689 // Add codecs that are not in |current_description| but were in |
1584 FindCodecsToOffer<AudioCodec>(supported_audio_codecs, audio_codecs, | 1690 // |remote_offer|. Do two passes, first adding codecs with payload types that |
1585 &used_pltypes); | 1691 // match the offer, then adding remaining codecs with remapped payload types. |
1586 FindCodecsToOffer<VideoCodec>(supported_video_codecs, video_codecs, | 1692 // |
1587 &used_pltypes); | 1693 // The two passes are needed so that a payload type isn't remapped to |
1588 FindCodecsToOffer<DataCodec>(supported_data_codecs, data_codecs, | 1694 // conflict with another codec. For example, PT "96" is in current |
1589 &used_pltypes); | 1695 // description, and a remote offer has "96" and "97". If "96" were remapped |
| 1696 // in the first pass (to "97", since that's the next number), that's now not |
| 1697 // available for "97", causing "97" to be remapped to "98" and a payload type |
| 1698 // to be wasted. |
| 1699 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, can_modify_codecs, |
| 1700 audio_codecs, &used_pltypes); |
| 1701 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, can_modify_codecs, |
| 1702 video_codecs, &used_pltypes); |
| 1703 MergeCodecs<DataCodec>(filtered_offered_data_codecs, can_modify_codecs, |
| 1704 data_codecs, &used_pltypes); |
| 1705 can_modify_codecs = true; |
| 1706 MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, can_modify_codecs, |
| 1707 audio_codecs, &used_pltypes); |
| 1708 MergeCodecs<VideoCodec>(filtered_offered_video_codecs, can_modify_codecs, |
| 1709 video_codecs, &used_pltypes); |
| 1710 MergeCodecs<DataCodec>(filtered_offered_data_codecs, can_modify_codecs, |
| 1711 data_codecs, &used_pltypes); |
1590 } | 1712 } |
1591 | 1713 |
1592 void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer( | 1714 void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer( |
1593 const SessionDescription* current_description, | 1715 const SessionDescription* current_description, |
1594 RtpHeaderExtensions* audio_extensions, | 1716 RtpHeaderExtensions* offer_audio_extensions, |
1595 RtpHeaderExtensions* video_extensions) const { | 1717 RtpHeaderExtensions* offer_video_extensions) const { |
1596 // All header extensions allocated from the same range to avoid potential | 1718 // All header extensions allocated from the same range to avoid potential |
1597 // issues when using BUNDLE. | 1719 // issues when using BUNDLE. |
1598 UsedRtpHeaderExtensionIds used_ids; | 1720 UsedRtpHeaderExtensionIds used_ids; |
1599 RtpHeaderExtensions all_extensions; | 1721 RtpHeaderExtensions all_extensions; |
1600 audio_extensions->clear(); | 1722 offer_audio_extensions->clear(); |
1601 video_extensions->clear(); | 1723 offer_video_extensions->clear(); |
1602 | 1724 |
1603 // First - get all extensions from the current description if the media type | 1725 // First - get all extensions from the current description if the media type |
1604 // is used. | 1726 // is used. Add them to |used_ids| so the local ids are not reused if a new |
1605 // Add them to |used_ids| so the local ids are not reused if a new media | 1727 // media type is added. |
1606 // type is added. | 1728 bool can_modify_extensions = false; |
1607 if (current_description) { | 1729 if (current_description) { |
1608 const AudioContentDescription* audio = | 1730 for (const ContentInfo& content : current_description->contents()) { |
1609 GetFirstAudioContentDescription(current_description); | 1731 if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) { |
1610 if (audio) { | 1732 continue; |
1611 *audio_extensions = audio->rtp_header_extensions(); | 1733 } |
1612 FindAndSetRtpHdrExtUsed(audio_extensions, &all_extensions, &used_ids); | 1734 if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) { |
1613 } | 1735 const AudioContentDescription* audio = |
1614 const VideoContentDescription* video = | 1736 static_cast<const AudioContentDescription*>(content.description); |
1615 GetFirstVideoContentDescription(current_description); | 1737 MergeRtpHdrExts(audio->rtp_header_extensions(), can_modify_extensions, |
1616 if (video) { | 1738 offer_audio_extensions, &all_extensions, &used_ids); |
1617 *video_extensions = video->rtp_header_extensions(); | 1739 } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) { |
1618 FindAndSetRtpHdrExtUsed(video_extensions, &all_extensions, &used_ids); | 1740 const VideoContentDescription* video = |
| 1741 static_cast<const VideoContentDescription*>(content.description); |
| 1742 MergeRtpHdrExts(video->rtp_header_extensions(), can_modify_extensions, |
| 1743 offer_video_extensions, &all_extensions, &used_ids); |
| 1744 } |
1619 } | 1745 } |
1620 } | 1746 } |
| 1747 // TODO: Do this for answer too? |
1621 | 1748 |
1622 // Add our default RTP header extensions that are not in | 1749 // Add our default RTP header extensions that are not in |
1623 // |current_description|. | 1750 // |current_description|. |
1624 FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions, | 1751 can_modify_extensions = true; |
1625 &all_extensions, &used_ids); | 1752 MergeRtpHdrExts(audio_rtp_header_extensions(), can_modify_extensions, |
1626 FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions, | 1753 offer_audio_extensions, &all_extensions, &used_ids); |
1627 &all_extensions, &used_ids); | 1754 MergeRtpHdrExts(video_rtp_header_extensions(), can_modify_extensions, |
| 1755 offer_video_extensions, &all_extensions, &used_ids); |
1628 } | 1756 } |
1629 | 1757 |
1630 bool MediaSessionDescriptionFactory::AddTransportOffer( | 1758 bool MediaSessionDescriptionFactory::AddTransportOffer( |
1631 const std::string& content_name, | 1759 const std::string& content_name, |
1632 const TransportOptions& transport_options, | 1760 const TransportOptions& transport_options, |
1633 const SessionDescription* current_desc, | 1761 const SessionDescription* current_desc, |
1634 SessionDescription* offer_desc) const { | 1762 SessionDescription* offer_desc) const { |
1635 if (!transport_desc_factory_) | 1763 if (!transport_desc_factory_) |
1636 return false; | 1764 return false; |
1637 const TransportDescription* current_tdesc = | 1765 const TransportDescription* current_tdesc = |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 if (!answer_desc->AddTransportInfo(TransportInfo(content_name, | 1798 if (!answer_desc->AddTransportInfo(TransportInfo(content_name, |
1671 transport_desc))) { | 1799 transport_desc))) { |
1672 LOG(LS_ERROR) | 1800 LOG(LS_ERROR) |
1673 << "Failed to AddTransportAnswer, content name=" << content_name; | 1801 << "Failed to AddTransportAnswer, content name=" << content_name; |
1674 return false; | 1802 return false; |
1675 } | 1803 } |
1676 return true; | 1804 return true; |
1677 } | 1805 } |
1678 | 1806 |
1679 bool MediaSessionDescriptionFactory::AddAudioContentForOffer( | 1807 bool MediaSessionDescriptionFactory::AddAudioContentForOffer( |
1680 const MediaSessionOptions& options, | 1808 const MediaDescriptionOptions& media_description_options, |
| 1809 const MediaSessionOptions& session_options, |
| 1810 const ContentInfo* current_content, |
1681 const SessionDescription* current_description, | 1811 const SessionDescription* current_description, |
1682 const RtpHeaderExtensions& audio_rtp_extensions, | 1812 const RtpHeaderExtensions& audio_rtp_extensions, |
1683 const AudioCodecs& audio_codecs, | 1813 const AudioCodecs& audio_codecs, |
1684 StreamParamsVec* current_streams, | 1814 StreamParamsVec* current_streams, |
1685 SessionDescription* desc) const { | 1815 SessionDescription* desc) const { |
1686 const ContentInfo* current_audio_content = | 1816 // Filter audio_codecs (which includes all codecs, with correctly remapped |
1687 GetFirstAudioContent(current_description); | 1817 // payload types) based on transceiver direction. |
1688 std::string content_name = | 1818 const AudioCodecs& supported_audio_codecs = |
1689 current_audio_content ? current_audio_content->name : CN_AUDIO; | 1819 GetAudioCodecsForOffer(media_description_options.direction); |
| 1820 AudioCodecs filtered_codecs; |
| 1821 for (const AudioCodec& codec : audio_codecs) { |
| 1822 if (FindMatchingCodec<AudioCodec>(audio_codecs, supported_audio_codecs, |
| 1823 codec, nullptr)) { |
| 1824 filtered_codecs.push_back(codec); |
| 1825 } |
| 1826 } |
1690 | 1827 |
1691 cricket::SecurePolicy sdes_policy = | 1828 cricket::SecurePolicy sdes_policy = |
1692 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED | 1829 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED |
1693 : secure(); | 1830 : secure(); |
1694 | 1831 |
1695 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription()); | 1832 std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription()); |
1696 std::vector<std::string> crypto_suites; | 1833 std::vector<std::string> crypto_suites; |
1697 GetSupportedAudioCryptoSuiteNames(options.crypto_options, &crypto_suites); | 1834 GetSupportedAudioCryptoSuiteNames(session_options.crypto_options, |
| 1835 &crypto_suites); |
1698 if (!CreateMediaContentOffer( | 1836 if (!CreateMediaContentOffer( |
1699 options, | 1837 media_description_options.sender_options, session_options, |
1700 audio_codecs, | 1838 filtered_codecs, sdes_policy, GetCryptos(current_content), |
1701 sdes_policy, | 1839 crypto_suites, audio_rtp_extensions, current_streams, audio.get())) { |
1702 GetCryptos(GetFirstAudioContentDescription(current_description)), | |
1703 crypto_suites, | |
1704 audio_rtp_extensions, | |
1705 add_legacy_, | |
1706 current_streams, | |
1707 audio.get())) { | |
1708 return false; | 1840 return false; |
1709 } | 1841 } |
1710 audio->set_lang(lang_); | 1842 audio->set_lang(lang_); |
1711 | 1843 |
1712 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); | 1844 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); |
1713 SetMediaProtocol(secure_transport, audio.get()); | 1845 SetMediaProtocol(secure_transport, audio.get()); |
1714 | 1846 |
1715 auto offer_rtd = | 1847 audio->set_direction( |
1716 RtpTransceiverDirection(!audio->streams().empty(), options.recv_audio); | 1848 media_description_options.direction.ToMediaContentDirection()); |
1717 audio->set_direction(offer_rtd.ToMediaContentDirection()); | |
1718 | 1849 |
1719 desc->AddContent(content_name, NS_JINGLE_RTP, audio.release()); | 1850 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP, |
1720 if (!AddTransportOffer(content_name, | 1851 audio.release()); |
1721 GetTransportOptions(options, content_name), | 1852 if (!AddTransportOffer(media_description_options.mid, |
| 1853 media_description_options.transport_options, |
1722 current_description, desc)) { | 1854 current_description, desc)) { |
1723 return false; | 1855 return false; |
1724 } | 1856 } |
1725 | 1857 |
1726 return true; | 1858 return true; |
1727 } | 1859 } |
1728 | 1860 |
1729 bool MediaSessionDescriptionFactory::AddVideoContentForOffer( | 1861 bool MediaSessionDescriptionFactory::AddVideoContentForOffer( |
1730 const MediaSessionOptions& options, | 1862 const MediaDescriptionOptions& media_description_options, |
| 1863 const MediaSessionOptions& session_options, |
| 1864 const ContentInfo* current_content, |
1731 const SessionDescription* current_description, | 1865 const SessionDescription* current_description, |
1732 const RtpHeaderExtensions& video_rtp_extensions, | 1866 const RtpHeaderExtensions& video_rtp_extensions, |
1733 const VideoCodecs& video_codecs, | 1867 const VideoCodecs& video_codecs, |
1734 StreamParamsVec* current_streams, | 1868 StreamParamsVec* current_streams, |
1735 SessionDescription* desc) const { | 1869 SessionDescription* desc) const { |
1736 const ContentInfo* current_video_content = | 1870 // Filter video_codecs (which includes all codecs, with correctly remapped |
1737 GetFirstVideoContent(current_description); | 1871 // payload types). |
1738 std::string content_name = | 1872 VideoCodecs filtered_codecs; |
1739 current_video_content ? current_video_content->name : CN_VIDEO; | 1873 for (const VideoCodec& codec : video_codecs) { |
| 1874 if (FindMatchingCodec<VideoCodec>(video_codecs, video_codecs_, codec, |
| 1875 nullptr)) { |
| 1876 filtered_codecs.push_back(codec); |
| 1877 } |
| 1878 } |
1740 | 1879 |
1741 cricket::SecurePolicy sdes_policy = | 1880 cricket::SecurePolicy sdes_policy = |
1742 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED | 1881 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED |
1743 : secure(); | 1882 : secure(); |
1744 | 1883 |
1745 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription()); | 1884 std::unique_ptr<VideoContentDescription> video(new VideoContentDescription()); |
1746 std::vector<std::string> crypto_suites; | 1885 std::vector<std::string> crypto_suites; |
1747 GetSupportedVideoCryptoSuiteNames(options.crypto_options, &crypto_suites); | 1886 GetSupportedVideoCryptoSuiteNames(session_options.crypto_options, |
| 1887 &crypto_suites); |
1748 if (!CreateMediaContentOffer( | 1888 if (!CreateMediaContentOffer( |
1749 options, | 1889 media_description_options.sender_options, session_options, |
1750 video_codecs, | 1890 filtered_codecs, sdes_policy, GetCryptos(current_content), |
1751 sdes_policy, | 1891 crypto_suites, video_rtp_extensions, current_streams, video.get())) { |
1752 GetCryptos(GetFirstVideoContentDescription(current_description)), | |
1753 crypto_suites, | |
1754 video_rtp_extensions, | |
1755 add_legacy_, | |
1756 current_streams, | |
1757 video.get())) { | |
1758 return false; | 1892 return false; |
1759 } | 1893 } |
1760 | 1894 video->set_bandwidth(kAutoBandwidth); |
1761 video->set_bandwidth(options.video_bandwidth); | |
1762 | 1895 |
1763 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); | 1896 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); |
1764 SetMediaProtocol(secure_transport, video.get()); | 1897 SetMediaProtocol(secure_transport, video.get()); |
1765 | 1898 |
1766 if (!video->streams().empty()) { | 1899 video->set_direction( |
1767 if (options.recv_video) { | 1900 media_description_options.direction.ToMediaContentDirection()); |
1768 video->set_direction(MD_SENDRECV); | |
1769 } else { | |
1770 video->set_direction(MD_SENDONLY); | |
1771 } | |
1772 } else { | |
1773 if (options.recv_video) { | |
1774 video->set_direction(MD_RECVONLY); | |
1775 } else { | |
1776 video->set_direction(MD_INACTIVE); | |
1777 } | |
1778 } | |
1779 | 1901 |
1780 desc->AddContent(content_name, NS_JINGLE_RTP, video.release()); | 1902 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP, |
1781 if (!AddTransportOffer(content_name, | 1903 video.release()); |
1782 GetTransportOptions(options, content_name), | 1904 if (!AddTransportOffer(media_description_options.mid, |
| 1905 media_description_options.transport_options, |
1783 current_description, desc)) { | 1906 current_description, desc)) { |
1784 return false; | 1907 return false; |
1785 } | 1908 } |
1786 | |
1787 return true; | 1909 return true; |
1788 } | 1910 } |
1789 | 1911 |
1790 bool MediaSessionDescriptionFactory::AddDataContentForOffer( | 1912 bool MediaSessionDescriptionFactory::AddDataContentForOffer( |
1791 const MediaSessionOptions& options, | 1913 const MediaDescriptionOptions& media_description_options, |
| 1914 const MediaSessionOptions& session_options, |
| 1915 const ContentInfo* current_content, |
1792 const SessionDescription* current_description, | 1916 const SessionDescription* current_description, |
1793 DataCodecs* data_codecs, | 1917 const DataCodecs& data_codecs, |
1794 StreamParamsVec* current_streams, | 1918 StreamParamsVec* current_streams, |
1795 SessionDescription* desc) const { | 1919 SessionDescription* desc) const { |
1796 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); | 1920 bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED); |
1797 | 1921 |
1798 std::unique_ptr<DataContentDescription> data(new DataContentDescription()); | 1922 std::unique_ptr<DataContentDescription> data(new DataContentDescription()); |
1799 bool is_sctp = (options.data_channel_type == DCT_SCTP); | 1923 bool is_sctp = (session_options.data_channel_type == DCT_SCTP); |
1800 | |
1801 FilterDataCodecs(data_codecs, is_sctp); | |
1802 | |
1803 const ContentInfo* current_data_content = | |
1804 GetFirstDataContent(current_description); | |
1805 std::string content_name = | |
1806 current_data_content ? current_data_content->name : CN_DATA; | |
1807 | 1924 |
1808 cricket::SecurePolicy sdes_policy = | 1925 cricket::SecurePolicy sdes_policy = |
1809 IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED | 1926 IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED |
1810 : secure(); | 1927 : secure(); |
1811 std::vector<std::string> crypto_suites; | 1928 std::vector<std::string> crypto_suites; |
1812 if (is_sctp) { | 1929 if (is_sctp) { |
1813 // SDES doesn't make sense for SCTP, so we disable it, and we only | 1930 // SDES doesn't make sense for SCTP, so we disable it, and we only |
1814 // get SDES crypto suites for RTP-based data channels. | 1931 // get SDES crypto suites for RTP-based data channels. |
1815 sdes_policy = cricket::SEC_DISABLED; | 1932 sdes_policy = cricket::SEC_DISABLED; |
1816 // Unlike SetMediaProtocol below, we need to set the protocol | 1933 // Unlike SetMediaProtocol below, we need to set the protocol |
1817 // before we call CreateMediaContentOffer. Otherwise, | 1934 // before we call CreateMediaContentOffer. Otherwise, |
1818 // CreateMediaContentOffer won't know this is SCTP and will | 1935 // CreateMediaContentOffer won't know this is SCTP and will |
1819 // generate SSRCs rather than SIDs. | 1936 // generate SSRCs rather than SIDs. |
1820 data->set_protocol( | 1937 data->set_protocol( |
1821 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp); | 1938 secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp); |
1822 } else { | 1939 } else { |
1823 GetSupportedDataCryptoSuiteNames(options.crypto_options, &crypto_suites); | 1940 GetSupportedDataCryptoSuiteNames(session_options.crypto_options, |
| 1941 &crypto_suites); |
1824 } | 1942 } |
1825 | 1943 |
| 1944 // Even SCTP uses a "codec". |
1826 if (!CreateMediaContentOffer( | 1945 if (!CreateMediaContentOffer( |
1827 options, | 1946 media_description_options.sender_options, session_options, |
1828 *data_codecs, | 1947 data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites, |
1829 sdes_policy, | 1948 RtpHeaderExtensions(), current_streams, data.get())) { |
1830 GetCryptos(GetFirstDataContentDescription(current_description)), | |
1831 crypto_suites, | |
1832 RtpHeaderExtensions(), | |
1833 add_legacy_, | |
1834 current_streams, | |
1835 data.get())) { | |
1836 return false; | 1949 return false; |
1837 } | 1950 } |
1838 | 1951 |
1839 if (is_sctp) { | 1952 if (is_sctp) { |
1840 desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release()); | 1953 desc->AddContent(media_description_options.mid, NS_JINGLE_DRAFT_SCTP, |
| 1954 data.release()); |
1841 } else { | 1955 } else { |
1842 data->set_bandwidth(options.data_bandwidth); | 1956 data->set_bandwidth(kDataMaxBandwidth); |
1843 SetMediaProtocol(secure_transport, data.get()); | 1957 SetMediaProtocol(secure_transport, data.get()); |
1844 desc->AddContent(content_name, NS_JINGLE_RTP, data.release()); | 1958 desc->AddContent(media_description_options.mid, NS_JINGLE_RTP, |
| 1959 data.release()); |
1845 } | 1960 } |
1846 if (!AddTransportOffer(content_name, | 1961 if (!AddTransportOffer(media_description_options.mid, |
1847 GetTransportOptions(options, content_name), | 1962 media_description_options.transport_options, |
1848 current_description, desc)) { | 1963 current_description, desc)) { |
1849 return false; | 1964 return false; |
1850 } | 1965 } |
1851 return true; | 1966 return true; |
1852 } | 1967 } |
1853 | 1968 |
1854 bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( | 1969 bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( |
1855 const SessionDescription* offer, | 1970 const MediaDescriptionOptions& media_description_options, |
1856 const MediaSessionOptions& options, | 1971 const MediaSessionOptions& session_options, |
| 1972 const ContentInfo* offer_content, |
| 1973 const SessionDescription* offer_description, |
| 1974 const ContentInfo* current_content, |
1857 const SessionDescription* current_description, | 1975 const SessionDescription* current_description, |
| 1976 const AudioCodecs& audio_codecs, |
1858 StreamParamsVec* current_streams, | 1977 StreamParamsVec* current_streams, |
1859 SessionDescription* answer) const { | 1978 SessionDescription* answer) const { |
1860 const ContentInfo* audio_content = GetFirstAudioContent(offer); | 1979 const AudioContentDescription* offer_audio_description = |
1861 const AudioContentDescription* offer_audio = | 1980 static_cast<const AudioContentDescription*>(offer_content->description); |
1862 static_cast<const AudioContentDescription*>(audio_content->description); | |
1863 | 1981 |
1864 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer( | 1982 std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer( |
1865 audio_content->name, offer, | 1983 media_description_options.mid, offer_description, |
1866 GetTransportOptions(options, audio_content->name), current_description)); | 1984 media_description_options.transport_options, current_description)); |
1867 if (!audio_transport) { | 1985 if (!audio_transport) { |
1868 return false; | 1986 return false; |
1869 } | 1987 } |
1870 | 1988 |
1871 // Pick codecs based on the requested communications direction in the offer. | 1989 // Pick codecs based on the requested communications direction in the offer |
1872 const bool wants_send = | 1990 // and the selected direction in the answer. |
1873 options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_; | 1991 // Note these will be filtered one final time in CreateMediaContentAnswer. |
1874 auto wants_rtd = RtpTransceiverDirection(wants_send, options.recv_audio); | 1992 auto wants_rtd = media_description_options.direction; |
1875 auto offer_rtd = | 1993 auto offer_rtd = RtpTransceiverDirection::FromMediaContentDirection( |
1876 RtpTransceiverDirection::FromMediaContentDirection( | 1994 offer_audio_description->direction()); |
1877 offer_audio->direction()); | |
1878 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd); | 1995 auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd); |
1879 AudioCodecs audio_codecs = GetAudioCodecsForAnswer(offer_rtd, answer_rtd); | 1996 const AudioCodecs& supported_audio_codecs = |
1880 if (!options.vad_enabled) { | 1997 GetAudioCodecsForAnswer(offer_rtd, answer_rtd); |
1881 StripCNCodecs(&audio_codecs); | 1998 AudioCodecs filtered_codecs; |
| 1999 for (const AudioCodec& codec : audio_codecs) { |
| 2000 if (FindMatchingCodec<AudioCodec>(audio_codecs, supported_audio_codecs, |
| 2001 codec, nullptr) && |
| 2002 FindMatchingCodec<AudioCodec>(audio_codecs, supported_audio_codecs, |
| 2003 codec, nullptr)) { |
| 2004 filtered_codecs.push_back(codec); |
| 2005 } |
1882 } | 2006 } |
1883 | 2007 |
1884 bool bundle_enabled = | 2008 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) && |
1885 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled; | 2009 session_options.bundle_enabled; |
1886 std::unique_ptr<AudioContentDescription> audio_answer( | 2010 std::unique_ptr<AudioContentDescription> audio_answer( |
1887 new AudioContentDescription()); | 2011 new AudioContentDescription()); |
1888 // Do not require or create SDES cryptos if DTLS is used. | 2012 // Do not require or create SDES cryptos if DTLS is used. |
1889 cricket::SecurePolicy sdes_policy = | 2013 cricket::SecurePolicy sdes_policy = |
1890 audio_transport->secure() ? cricket::SEC_DISABLED : secure(); | 2014 audio_transport->secure() ? cricket::SEC_DISABLED : secure(); |
1891 if (!CreateMediaContentAnswer( | 2015 if (!CreateMediaContentAnswer( |
1892 offer_audio, | 2016 offer_audio_description, media_description_options.sender_options, |
1893 options, | 2017 media_description_options.direction, session_options, filtered_codecs, |
1894 audio_codecs, | 2018 sdes_policy, GetCryptos(current_content), audio_rtp_extensions_, |
1895 sdes_policy, | 2019 current_streams, bundle_enabled, audio_answer.get())) { |
1896 GetCryptos(GetFirstAudioContentDescription(current_description)), | |
1897 audio_rtp_extensions_, | |
1898 current_streams, | |
1899 add_legacy_, | |
1900 bundle_enabled, | |
1901 audio_answer.get())) { | |
1902 return false; // Fails the session setup. | 2020 return false; // Fails the session setup. |
1903 } | 2021 } |
1904 | 2022 |
1905 bool rejected = !options.has_audio() || audio_content->rejected || | 2023 bool rejected = |
1906 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, | 2024 media_description_options.stopped || offer_content->rejected || |
1907 audio_answer->protocol(), | 2025 !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, audio_answer->protocol(), |
1908 audio_transport->secure()); | 2026 audio_transport->secure()); |
1909 if (!rejected) { | 2027 if (!rejected) { |
1910 AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer); | 2028 AddTransportAnswer(media_description_options.mid, *(audio_transport.get()), |
| 2029 answer); |
1911 } else { | 2030 } else { |
1912 // RFC 3264 | 2031 LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid |
1913 // The answer MUST contain the same number of m-lines as the offer. | 2032 << "' being rejected in answer."; |
1914 LOG(LS_INFO) << "Audio is not supported in the answer."; | |
1915 } | 2033 } |
1916 | 2034 |
1917 answer->AddContent(audio_content->name, audio_content->type, rejected, | 2035 answer->AddContent(media_description_options.mid, offer_content->type, |
1918 audio_answer.release()); | 2036 rejected, audio_answer.release()); |
1919 return true; | 2037 return true; |
1920 } | 2038 } |
1921 | 2039 |
1922 bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( | 2040 bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( |
1923 const SessionDescription* offer, | 2041 const MediaDescriptionOptions& media_description_options, |
1924 const MediaSessionOptions& options, | 2042 const MediaSessionOptions& session_options, |
| 2043 const ContentInfo* offer_content, |
| 2044 const SessionDescription* offer_description, |
| 2045 const ContentInfo* current_content, |
1925 const SessionDescription* current_description, | 2046 const SessionDescription* current_description, |
| 2047 const VideoCodecs& video_codecs, |
1926 StreamParamsVec* current_streams, | 2048 StreamParamsVec* current_streams, |
1927 SessionDescription* answer) const { | 2049 SessionDescription* answer) const { |
1928 const ContentInfo* video_content = GetFirstVideoContent(offer); | 2050 const VideoContentDescription* offer_video_description = |
| 2051 static_cast<const VideoContentDescription*>(offer_content->description); |
| 2052 |
1929 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer( | 2053 std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer( |
1930 video_content->name, offer, | 2054 media_description_options.mid, offer_description, |
1931 GetTransportOptions(options, video_content->name), current_description)); | 2055 media_description_options.transport_options, current_description)); |
1932 if (!video_transport) { | 2056 if (!video_transport) { |
1933 return false; | 2057 return false; |
1934 } | 2058 } |
1935 | 2059 |
| 2060 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) && |
| 2061 session_options.bundle_enabled; |
1936 std::unique_ptr<VideoContentDescription> video_answer( | 2062 std::unique_ptr<VideoContentDescription> video_answer( |
1937 new VideoContentDescription()); | 2063 new VideoContentDescription()); |
1938 // Do not require or create SDES cryptos if DTLS is used. | 2064 // Do not require or create SDES cryptos if DTLS is used. |
1939 cricket::SecurePolicy sdes_policy = | 2065 cricket::SecurePolicy sdes_policy = |
1940 video_transport->secure() ? cricket::SEC_DISABLED : secure(); | 2066 video_transport->secure() ? cricket::SEC_DISABLED : secure(); |
1941 bool bundle_enabled = | |
1942 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled; | |
1943 if (!CreateMediaContentAnswer( | 2067 if (!CreateMediaContentAnswer( |
1944 static_cast<const VideoContentDescription*>( | 2068 offer_video_description, media_description_options.sender_options, |
1945 video_content->description), | 2069 media_description_options.direction, session_options, video_codecs, |
1946 options, | 2070 sdes_policy, GetCryptos(current_content), video_rtp_extensions_, |
1947 video_codecs_, | 2071 current_streams, bundle_enabled, video_answer.get())) { |
1948 sdes_policy, | 2072 return false; // Fails the session setup. |
1949 GetCryptos(GetFirstVideoContentDescription(current_description)), | |
1950 video_rtp_extensions_, | |
1951 current_streams, | |
1952 add_legacy_, | |
1953 bundle_enabled, | |
1954 video_answer.get())) { | |
1955 return false; | |
1956 } | 2073 } |
1957 bool rejected = !options.has_video() || video_content->rejected || | 2074 |
1958 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, | 2075 bool rejected = |
1959 video_answer->protocol(), | 2076 media_description_options.stopped || offer_content->rejected || |
| 2077 !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, video_answer->protocol(), |
1960 video_transport->secure()); | 2078 video_transport->secure()); |
1961 if (!rejected) { | 2079 if (!rejected) { |
1962 if (!AddTransportAnswer(video_content->name, *(video_transport.get()), | 2080 if (!AddTransportAnswer(media_description_options.mid, |
1963 answer)) { | 2081 *(video_transport.get()), answer)) { |
1964 return false; | 2082 return false; |
1965 } | 2083 } |
1966 video_answer->set_bandwidth(options.video_bandwidth); | 2084 video_answer->set_bandwidth(kAutoBandwidth); |
1967 } else { | 2085 } else { |
1968 // RFC 3264 | 2086 LOG(LS_INFO) << "Video m= section '" << media_description_options.mid |
1969 // The answer MUST contain the same number of m-lines as the offer. | 2087 << "' being rejected in answer."; |
1970 LOG(LS_INFO) << "Video is not supported in the answer."; | |
1971 } | 2088 } |
1972 answer->AddContent(video_content->name, video_content->type, rejected, | 2089 |
1973 video_answer.release()); | 2090 answer->AddContent(media_description_options.mid, offer_content->type, |
| 2091 rejected, video_answer.release()); |
1974 return true; | 2092 return true; |
1975 } | 2093 } |
1976 | 2094 |
1977 bool MediaSessionDescriptionFactory::AddDataContentForAnswer( | 2095 bool MediaSessionDescriptionFactory::AddDataContentForAnswer( |
1978 const SessionDescription* offer, | 2096 const MediaDescriptionOptions& media_description_options, |
1979 const MediaSessionOptions& options, | 2097 const MediaSessionOptions& session_options, |
| 2098 const ContentInfo* offer_content, |
| 2099 const SessionDescription* offer_description, |
| 2100 const ContentInfo* current_content, |
1980 const SessionDescription* current_description, | 2101 const SessionDescription* current_description, |
| 2102 const DataCodecs& data_codecs, |
1981 StreamParamsVec* current_streams, | 2103 StreamParamsVec* current_streams, |
1982 SessionDescription* answer) const { | 2104 SessionDescription* answer) const { |
1983 const ContentInfo* data_content = GetFirstDataContent(offer); | |
1984 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer( | 2105 std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer( |
1985 data_content->name, offer, | 2106 media_description_options.mid, offer_description, |
1986 GetTransportOptions(options, data_content->name), current_description)); | 2107 media_description_options.transport_options, current_description)); |
1987 if (!data_transport) { | 2108 if (!data_transport) { |
1988 return false; | 2109 return false; |
1989 } | 2110 } |
1990 bool is_sctp = (options.data_channel_type == DCT_SCTP); | |
1991 std::vector<DataCodec> data_codecs(data_codecs_); | |
1992 FilterDataCodecs(&data_codecs, is_sctp); | |
1993 | 2111 |
1994 std::unique_ptr<DataContentDescription> data_answer( | 2112 std::unique_ptr<DataContentDescription> data_answer( |
1995 new DataContentDescription()); | 2113 new DataContentDescription()); |
1996 // Do not require or create SDES cryptos if DTLS is used. | 2114 // Do not require or create SDES cryptos if DTLS is used. |
1997 cricket::SecurePolicy sdes_policy = | 2115 cricket::SecurePolicy sdes_policy = |
1998 data_transport->secure() ? cricket::SEC_DISABLED : secure(); | 2116 data_transport->secure() ? cricket::SEC_DISABLED : secure(); |
1999 bool bundle_enabled = | 2117 bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) && |
2000 offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled; | 2118 session_options.bundle_enabled; |
2001 if (!CreateMediaContentAnswer( | 2119 if (!CreateMediaContentAnswer( |
2002 static_cast<const DataContentDescription*>( | 2120 static_cast<const DataContentDescription*>( |
2003 data_content->description), | 2121 offer_content->description), |
2004 options, | 2122 media_description_options.sender_options, |
2005 data_codecs_, | 2123 media_description_options.direction, session_options, data_codecs, |
2006 sdes_policy, | 2124 sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), |
2007 GetCryptos(GetFirstDataContentDescription(current_description)), | 2125 current_streams, bundle_enabled, data_answer.get())) { |
2008 RtpHeaderExtensions(), | |
2009 current_streams, | |
2010 add_legacy_, | |
2011 bundle_enabled, | |
2012 data_answer.get())) { | |
2013 return false; // Fails the session setup. | 2126 return false; // Fails the session setup. |
2014 } | 2127 } |
2015 | 2128 |
2016 bool rejected = !options.has_data() || data_content->rejected || | 2129 bool rejected = |
2017 !IsMediaProtocolSupported(MEDIA_TYPE_DATA, | 2130 media_description_options.stopped || offer_content->rejected || |
2018 data_answer->protocol(), | 2131 !IsMediaProtocolSupported(MEDIA_TYPE_DATA, data_answer->protocol(), |
2019 data_transport->secure()); | 2132 data_transport->secure()); |
2020 if (!rejected) { | 2133 if (!rejected) { |
2021 data_answer->set_bandwidth(options.data_bandwidth); | 2134 data_answer->set_bandwidth(kDataMaxBandwidth); |
2022 if (!AddTransportAnswer(data_content->name, *(data_transport.get()), | 2135 if (!AddTransportAnswer(media_description_options.mid, |
2023 answer)) { | 2136 *(data_transport.get()), answer)) { |
2024 return false; | 2137 return false; |
2025 } | 2138 } |
2026 } else { | 2139 } else { |
2027 // RFC 3264 | 2140 // RFC 3264 |
2028 // The answer MUST contain the same number of m-lines as the offer. | 2141 // The answer MUST contain the same number of m-lines as the offer. |
2029 LOG(LS_INFO) << "Data is not supported in the answer."; | 2142 LOG(LS_INFO) << "Data is not supported in the answer."; |
2030 } | 2143 } |
2031 answer->AddContent(data_content->name, data_content->type, rejected, | 2144 answer->AddContent(media_description_options.mid, offer_content->type, |
2032 data_answer.release()); | 2145 rejected, data_answer.release()); |
2033 return true; | 2146 return true; |
2034 } | 2147 } |
2035 | 2148 |
2036 bool IsMediaContent(const ContentInfo* content) { | 2149 bool IsMediaContent(const ContentInfo* content) { |
2037 return (content && | 2150 return (content && |
2038 (content->type == NS_JINGLE_RTP || | 2151 (content->type == NS_JINGLE_RTP || |
2039 content->type == NS_JINGLE_DRAFT_SCTP)); | 2152 content->type == NS_JINGLE_DRAFT_SCTP)); |
2040 } | 2153 } |
2041 | 2154 |
2042 bool IsAudioContent(const ContentInfo* content) { | 2155 bool IsAudioContent(const ContentInfo* content) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2186 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); | 2299 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO)); |
2187 } | 2300 } |
2188 | 2301 |
2189 DataContentDescription* GetFirstDataContentDescription( | 2302 DataContentDescription* GetFirstDataContentDescription( |
2190 SessionDescription* sdesc) { | 2303 SessionDescription* sdesc) { |
2191 return static_cast<DataContentDescription*>( | 2304 return static_cast<DataContentDescription*>( |
2192 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); | 2305 GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA)); |
2193 } | 2306 } |
2194 | 2307 |
2195 } // namespace cricket | 2308 } // namespace cricket |
OLD | NEW |