OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2012 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 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 ? desc->streams() | 126 ? desc->streams() |
127 : std::vector<cricket::StreamParams>(); | 127 : std::vector<cricket::StreamParams>(); |
128 } | 128 } |
129 | 129 |
130 bool IsValidOfferToReceiveMedia(int value) { | 130 bool IsValidOfferToReceiveMedia(int value) { |
131 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options; | 131 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options; |
132 return (value >= Options::kUndefined) && | 132 return (value >= Options::kUndefined) && |
133 (value <= Options::kMaxOfferToReceiveMedia); | 133 (value <= Options::kMaxOfferToReceiveMedia); |
134 } | 134 } |
135 | 135 |
136 // Add the stream and RTP data channel info to |session_options|. | 136 // Add options to |[audio/video]_media_description_options| from |senders|. |
137 void AddSendStreams( | 137 void AddRtpSenderOptions( |
138 cricket::MediaSessionOptions* session_options, | |
139 const std::vector<rtc::scoped_refptr< | 138 const std::vector<rtc::scoped_refptr< |
140 RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders, | 139 RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders, |
| 140 cricket::MediaDescriptionOptions* audio_media_description_options, |
| 141 cricket::MediaDescriptionOptions* video_media_description_options) { |
| 142 for (const auto& sender : senders) { |
| 143 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) { |
| 144 if (audio_media_description_options) { |
| 145 audio_media_description_options->AddAudioSender( |
| 146 sender->id(), sender->internal()->stream_id()); |
| 147 } |
| 148 } else { |
| 149 RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO); |
| 150 if (video_media_description_options) { |
| 151 video_media_description_options->AddVideoSender( |
| 152 sender->id(), sender->internal()->stream_id(), 1); |
| 153 } |
| 154 } |
| 155 } |
| 156 } |
| 157 |
| 158 // Add options to |session_options| from |rtp_data_channels|. |
| 159 void AddRtpDataChannelOptions( |
141 const std::map<std::string, rtc::scoped_refptr<DataChannel>>& | 160 const std::map<std::string, rtc::scoped_refptr<DataChannel>>& |
142 rtp_data_channels) { | 161 rtp_data_channels, |
143 session_options->streams.clear(); | 162 cricket::MediaDescriptionOptions* data_media_description_options) { |
144 for (const auto& sender : senders) { | 163 if (!data_media_description_options) { |
145 session_options->AddSendStream(sender->media_type(), sender->id(), | 164 return; |
146 sender->internal()->stream_id()); | |
147 } | 165 } |
148 | |
149 // Check for data channels. | 166 // Check for data channels. |
150 for (const auto& kv : rtp_data_channels) { | 167 for (const auto& kv : rtp_data_channels) { |
151 const DataChannel* channel = kv.second; | 168 const DataChannel* channel = kv.second; |
152 if (channel->state() == DataChannel::kConnecting || | 169 if (channel->state() == DataChannel::kConnecting || |
153 channel->state() == DataChannel::kOpen) { | 170 channel->state() == DataChannel::kOpen) { |
154 // |streamid| and |sync_label| are both set to the DataChannel label | 171 // Legacy RTP data channels are signaled with the track/stream ID set to |
155 // here so they can be signaled the same way as MediaStreams and Tracks. | 172 // the data channel's label. |
156 // For MediaStreams, the sync_label is the MediaStream label and the | 173 data_media_description_options->AddRtpDataChannel(channel->label(), |
157 // track label is the same as |streamid|. | 174 channel->label()); |
158 const std::string& streamid = channel->label(); | |
159 const std::string& sync_label = channel->label(); | |
160 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid, | |
161 sync_label); | |
162 } | 175 } |
163 } | 176 } |
164 } | 177 } |
165 | 178 |
166 uint32_t ConvertIceTransportTypeToCandidateFilter( | 179 uint32_t ConvertIceTransportTypeToCandidateFilter( |
167 PeerConnectionInterface::IceTransportsType type) { | 180 PeerConnectionInterface::IceTransportsType type) { |
168 switch (type) { | 181 switch (type) { |
169 case PeerConnectionInterface::kNone: | 182 case PeerConnectionInterface::kNone: |
170 return cricket::CF_NONE; | 183 return cricket::CF_NONE; |
171 case PeerConnectionInterface::kRelay: | 184 case PeerConnectionInterface::kRelay: |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 // Generate a RTCP CNAME when a PeerConnection is created. | 320 // Generate a RTCP CNAME when a PeerConnection is created. |
308 std::string GenerateRtcpCname() { | 321 std::string GenerateRtcpCname() { |
309 std::string cname; | 322 std::string cname; |
310 if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) { | 323 if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) { |
311 LOG(LS_ERROR) << "Failed to generate CNAME."; | 324 LOG(LS_ERROR) << "Failed to generate CNAME."; |
312 RTC_NOTREACHED(); | 325 RTC_NOTREACHED(); |
313 } | 326 } |
314 return cname; | 327 return cname; |
315 } | 328 } |
316 | 329 |
317 bool ExtractMediaSessionOptions( | 330 bool ValidateOfferAnswerOptions( |
| 331 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options) { |
| 332 return IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) && |
| 333 IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video); |
| 334 } |
| 335 |
| 336 // From |rtc_options|, fill parts of |session_options| shared by all generated |
| 337 // m= sections (in other words, nothing that involves a map/array). |
| 338 void ExtractSharedMediaSessionOptions( |
318 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, | 339 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, |
319 bool is_offer, | |
320 cricket::MediaSessionOptions* session_options) { | 340 cricket::MediaSessionOptions* session_options) { |
321 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions; | 341 session_options->vad_enabled = rtc_options.voice_activity_detection; |
322 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) || | 342 session_options->bundle_enabled = rtc_options.use_rtp_mux; |
323 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) { | 343 } |
324 return false; | 344 |
| 345 bool ConvertConstraintsToOfferAnswerOptions( |
| 346 const MediaConstraintsInterface* constraints, |
| 347 PeerConnectionInterface::RTCOfferAnswerOptions* offer_answer_options) { |
| 348 if (!constraints) { |
| 349 return true; |
325 } | 350 } |
326 | 351 |
327 // If constraints don't prevent us, we always accept video. | |
328 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { | |
329 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0); | |
330 } else { | |
331 session_options->recv_audio = true; | |
332 } | |
333 // For offers, we only offer video if we have it or it's forced by options. | |
334 // For answers, we will always accept video (if offered). | |
335 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { | |
336 session_options->recv_video = (rtc_options.offer_to_receive_video > 0); | |
337 } else if (is_offer) { | |
338 session_options->recv_video = false; | |
339 } else { | |
340 session_options->recv_video = true; | |
341 } | |
342 | |
343 session_options->vad_enabled = rtc_options.voice_activity_detection; | |
344 session_options->bundle_enabled = rtc_options.use_rtp_mux; | |
345 for (auto& kv : session_options->transport_options) { | |
346 kv.second.ice_restart = rtc_options.ice_restart; | |
347 } | |
348 | |
349 return true; | |
350 } | |
351 | |
352 bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints, | |
353 cricket::MediaSessionOptions* session_options) { | |
354 bool value = false; | 352 bool value = false; |
355 size_t mandatory_constraints_satisfied = 0; | 353 size_t mandatory_constraints_satisfied = 0; |
356 | 354 |
357 // kOfferToReceiveAudio defaults to true according to spec. | 355 if (FindConstraint(constraints, |
358 if (!FindConstraint(constraints, | 356 MediaConstraintsInterface::kOfferToReceiveAudio, &value, |
359 MediaConstraintsInterface::kOfferToReceiveAudio, &value, | 357 &mandatory_constraints_satisfied)) { |
360 &mandatory_constraints_satisfied) || | 358 offer_answer_options->offer_to_receive_audio = |
361 value) { | 359 value ? PeerConnectionInterface::RTCOfferAnswerOptions:: |
362 session_options->recv_audio = true; | 360 kOfferToReceiveMediaTrue |
363 } | 361 : 0; |
364 | |
365 // kOfferToReceiveVideo defaults to false according to spec. But | |
366 // if it is an answer and video is offered, we should still accept video | |
367 // per default. | |
368 value = false; | |
369 if (!FindConstraint(constraints, | |
370 MediaConstraintsInterface::kOfferToReceiveVideo, &value, | |
371 &mandatory_constraints_satisfied) || | |
372 value) { | |
373 session_options->recv_video = true; | |
374 } | 362 } |
375 | 363 |
376 if (FindConstraint(constraints, | 364 if (FindConstraint(constraints, |
| 365 MediaConstraintsInterface::kOfferToReceiveVideo, &value, |
| 366 &mandatory_constraints_satisfied)) { |
| 367 offer_answer_options->offer_to_receive_video = |
| 368 value ? PeerConnectionInterface::RTCOfferAnswerOptions:: |
| 369 kOfferToReceiveMediaTrue |
| 370 : 0; |
| 371 } |
| 372 if (FindConstraint(constraints, |
377 MediaConstraintsInterface::kVoiceActivityDetection, &value, | 373 MediaConstraintsInterface::kVoiceActivityDetection, &value, |
378 &mandatory_constraints_satisfied)) { | 374 &mandatory_constraints_satisfied)) { |
379 session_options->vad_enabled = value; | 375 offer_answer_options->voice_activity_detection = value; |
| 376 } |
| 377 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value, |
| 378 &mandatory_constraints_satisfied)) { |
| 379 offer_answer_options->use_rtp_mux = value; |
| 380 } |
| 381 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart, |
| 382 &value, &mandatory_constraints_satisfied)) { |
| 383 offer_answer_options->ice_restart = value; |
380 } | 384 } |
381 | 385 |
382 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value, | |
383 &mandatory_constraints_satisfied)) { | |
384 session_options->bundle_enabled = value; | |
385 } else { | |
386 // kUseRtpMux defaults to true according to spec. | |
387 session_options->bundle_enabled = true; | |
388 } | |
389 | |
390 bool ice_restart = false; | |
391 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart, | |
392 &value, &mandatory_constraints_satisfied)) { | |
393 // kIceRestart defaults to false according to spec. | |
394 ice_restart = true; | |
395 } | |
396 for (auto& kv : session_options->transport_options) { | |
397 kv.second.ice_restart = ice_restart; | |
398 } | |
399 | |
400 if (!constraints) { | |
401 return true; | |
402 } | |
403 return mandatory_constraints_satisfied == constraints->GetMandatory().size(); | 386 return mandatory_constraints_satisfied == constraints->GetMandatory().size(); |
404 } | 387 } |
405 | 388 |
406 PeerConnection::PeerConnection(PeerConnectionFactory* factory, | 389 PeerConnection::PeerConnection(PeerConnectionFactory* factory, |
407 std::unique_ptr<RtcEventLog> event_log, | 390 std::unique_ptr<RtcEventLog> event_log, |
408 std::unique_ptr<Call> call) | 391 std::unique_ptr<Call> call) |
409 : factory_(factory), | 392 : factory_(factory), |
410 observer_(NULL), | 393 observer_(NULL), |
411 uma_observer_(NULL), | 394 uma_observer_(NULL), |
412 event_log_(std::move(event_log)), | 395 event_log_(std::move(event_log)), |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 return DataChannelProxy::Create(signaling_thread(), channel.get()); | 818 return DataChannelProxy::Create(signaling_thread(), channel.get()); |
836 } | 819 } |
837 | 820 |
838 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, | 821 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, |
839 const MediaConstraintsInterface* constraints) { | 822 const MediaConstraintsInterface* constraints) { |
840 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); | 823 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); |
841 if (!observer) { | 824 if (!observer) { |
842 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; | 825 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; |
843 return; | 826 return; |
844 } | 827 } |
845 RTCOfferAnswerOptions options; | 828 PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options; |
| 829 // Always create an offer even if |ConvertConstraintsToOfferAnswerOptions| |
| 830 // returns false for now. Because |ConvertConstraintsToOfferAnswerOptions| |
| 831 // compares the mandatory fields parsed with the mandatory fields added in the |
| 832 // |constraints| and some downstream applications might create offers with |
| 833 // mandatory fields which would not be parsed in the helper method. For |
| 834 // example, in Chromium/remoting, |kEnableDtlsSrtp| is added to the |
| 835 // |constraints| as a mandatory field but it is not parsed. |
| 836 ConvertConstraintsToOfferAnswerOptions(constraints, &offer_answer_options); |
846 | 837 |
847 bool value; | 838 CreateOffer(observer, offer_answer_options); |
848 size_t mandatory_constraints = 0; | |
849 | |
850 if (FindConstraint(constraints, | |
851 MediaConstraintsInterface::kOfferToReceiveAudio, | |
852 &value, | |
853 &mandatory_constraints)) { | |
854 options.offer_to_receive_audio = | |
855 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0; | |
856 } | |
857 | |
858 if (FindConstraint(constraints, | |
859 MediaConstraintsInterface::kOfferToReceiveVideo, | |
860 &value, | |
861 &mandatory_constraints)) { | |
862 options.offer_to_receive_video = | |
863 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0; | |
864 } | |
865 | |
866 if (FindConstraint(constraints, | |
867 MediaConstraintsInterface::kVoiceActivityDetection, | |
868 &value, | |
869 &mandatory_constraints)) { | |
870 options.voice_activity_detection = value; | |
871 } | |
872 | |
873 if (FindConstraint(constraints, | |
874 MediaConstraintsInterface::kIceRestart, | |
875 &value, | |
876 &mandatory_constraints)) { | |
877 options.ice_restart = value; | |
878 } | |
879 | |
880 if (FindConstraint(constraints, | |
881 MediaConstraintsInterface::kUseRtpMux, | |
882 &value, | |
883 &mandatory_constraints)) { | |
884 options.use_rtp_mux = value; | |
885 } | |
886 | |
887 CreateOffer(observer, options); | |
888 } | 839 } |
889 | 840 |
890 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, | 841 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, |
891 const RTCOfferAnswerOptions& options) { | 842 const RTCOfferAnswerOptions& options) { |
892 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); | 843 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); |
893 if (!observer) { | 844 if (!observer) { |
894 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; | 845 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; |
895 return; | 846 return; |
896 } | 847 } |
897 | 848 |
898 cricket::MediaSessionOptions session_options; | 849 if (!ValidateOfferAnswerOptions(options)) { |
899 if (!GetOptionsForOffer(options, &session_options)) { | |
900 std::string error = "CreateOffer called with invalid options."; | 850 std::string error = "CreateOffer called with invalid options."; |
901 LOG(LS_ERROR) << error; | 851 LOG(LS_ERROR) << error; |
902 PostCreateSessionDescriptionFailure(observer, error); | 852 PostCreateSessionDescriptionFailure(observer, error); |
903 return; | 853 return; |
904 } | 854 } |
905 | 855 |
| 856 cricket::MediaSessionOptions session_options; |
| 857 GetOptionsForOffer(options, &session_options); |
906 session_->CreateOffer(observer, options, session_options); | 858 session_->CreateOffer(observer, options, session_options); |
907 } | 859 } |
908 | 860 |
909 void PeerConnection::CreateAnswer( | 861 void PeerConnection::CreateAnswer( |
910 CreateSessionDescriptionObserver* observer, | 862 CreateSessionDescriptionObserver* observer, |
911 const MediaConstraintsInterface* constraints) { | 863 const MediaConstraintsInterface* constraints) { |
912 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); | 864 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); |
913 if (!observer) { | 865 if (!observer) { |
914 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; | 866 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; |
915 return; | 867 return; |
916 } | 868 } |
917 | 869 |
918 cricket::MediaSessionOptions session_options; | 870 if (!session_->remote_description() || |
919 if (!GetOptionsForAnswer(constraints, &session_options)) { | 871 session_->remote_description()->type() != |
| 872 SessionDescriptionInterface::kOffer) { |
| 873 std::string error = "CreateAnswer called without remote offer."; |
| 874 LOG(LS_ERROR) << error; |
| 875 PostCreateSessionDescriptionFailure(observer, error); |
| 876 return; |
| 877 } |
| 878 |
| 879 PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options; |
| 880 if (!ConvertConstraintsToOfferAnswerOptions(constraints, |
| 881 &offer_answer_options)) { |
920 std::string error = "CreateAnswer called with invalid constraints."; | 882 std::string error = "CreateAnswer called with invalid constraints."; |
921 LOG(LS_ERROR) << error; | 883 LOG(LS_ERROR) << error; |
922 PostCreateSessionDescriptionFailure(observer, error); | 884 PostCreateSessionDescriptionFailure(observer, error); |
923 return; | 885 return; |
924 } | 886 } |
925 | 887 |
| 888 cricket::MediaSessionOptions session_options; |
| 889 GetOptionsForAnswer(offer_answer_options, &session_options); |
926 session_->CreateAnswer(observer, session_options); | 890 session_->CreateAnswer(observer, session_options); |
927 } | 891 } |
928 | 892 |
929 void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer, | 893 void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer, |
930 const RTCOfferAnswerOptions& options) { | 894 const RTCOfferAnswerOptions& options) { |
931 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); | 895 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); |
932 if (!observer) { | 896 if (!observer) { |
933 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; | 897 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; |
934 return; | 898 return; |
935 } | 899 } |
936 | 900 |
937 cricket::MediaSessionOptions session_options; | 901 cricket::MediaSessionOptions session_options; |
938 if (!GetOptionsForAnswer(options, &session_options)) { | 902 GetOptionsForAnswer(options, &session_options); |
939 std::string error = "CreateAnswer called with invalid options."; | |
940 LOG(LS_ERROR) << error; | |
941 PostCreateSessionDescriptionFailure(observer, error); | |
942 return; | |
943 } | |
944 | 903 |
945 session_->CreateAnswer(observer, session_options); | 904 session_->CreateAnswer(observer, session_options); |
946 } | 905 } |
947 | 906 |
948 void PeerConnection::SetLocalDescription( | 907 void PeerConnection::SetLocalDescription( |
949 SetSessionDescriptionObserver* observer, | 908 SetSessionDescriptionObserver* observer, |
950 SessionDescriptionInterface* desc) { | 909 SessionDescriptionInterface* desc) { |
951 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription"); | 910 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription"); |
952 if (IsClosed()) { | 911 if (IsClosed()) { |
953 return; | 912 return; |
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1691 | 1650 |
1692 void PeerConnection::PostCreateSessionDescriptionFailure( | 1651 void PeerConnection::PostCreateSessionDescriptionFailure( |
1693 CreateSessionDescriptionObserver* observer, | 1652 CreateSessionDescriptionObserver* observer, |
1694 const std::string& error) { | 1653 const std::string& error) { |
1695 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | 1654 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); |
1696 msg->error = error; | 1655 msg->error = error; |
1697 signaling_thread()->Post(RTC_FROM_HERE, this, | 1656 signaling_thread()->Post(RTC_FROM_HERE, this, |
1698 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); | 1657 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); |
1699 } | 1658 } |
1700 | 1659 |
1701 bool PeerConnection::GetOptionsForOffer( | 1660 void PeerConnection::GetOptionsForOffer( |
1702 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, | 1661 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, |
1703 cricket::MediaSessionOptions* session_options) { | 1662 cricket::MediaSessionOptions* session_options) { |
1704 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of | 1663 ExtractSharedMediaSessionOptions(rtc_options, session_options); |
1705 // ContentInfos. | 1664 |
| 1665 // Figure out transceiver directional preferences. |
| 1666 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO); |
| 1667 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO); |
| 1668 |
| 1669 // By default, generate sendrecv/recvonly m= sections. |
| 1670 bool recv_audio = true; |
| 1671 bool recv_video = true; |
| 1672 |
| 1673 // By default, only offer a new m= section if we have media to send with it. |
| 1674 bool offer_new_audio_description = send_audio; |
| 1675 bool offer_new_video_description = send_video; |
| 1676 bool offer_new_data_description = HasDataChannels(); |
| 1677 |
| 1678 // The "offer_to_receive_X" options allow those defaults to be overridden. |
| 1679 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { |
| 1680 recv_audio = (rtc_options.offer_to_receive_audio > 0); |
| 1681 offer_new_audio_description = |
| 1682 offer_new_audio_description || (rtc_options.offer_to_receive_audio > 0); |
| 1683 } |
| 1684 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { |
| 1685 recv_video = (rtc_options.offer_to_receive_video > 0); |
| 1686 offer_new_video_description = |
| 1687 offer_new_video_description || (rtc_options.offer_to_receive_video > 0); |
| 1688 } |
| 1689 |
| 1690 rtc::Optional<size_t> audio_index; |
| 1691 rtc::Optional<size_t> video_index; |
| 1692 rtc::Optional<size_t> data_index; |
| 1693 // If a current description exists, generate m= sections in the same order, |
| 1694 // using the first audio/video/data section that appears and rejecting |
| 1695 // extraneous ones. |
1706 if (session_->local_description()) { | 1696 if (session_->local_description()) { |
1707 for (const cricket::ContentInfo& content : | 1697 GenerateMediaDescriptionOptions( |
1708 session_->local_description()->description()->contents()) { | 1698 session_->local_description(), |
1709 session_options->transport_options[content.name] = | 1699 cricket::RtpTransceiverDirection(send_audio, recv_audio), |
1710 cricket::TransportOptions(); | 1700 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index, |
1711 } | 1701 &video_index, &data_index, session_options); |
1712 } | 1702 } |
1713 session_options->enable_ice_renomination = | 1703 |
1714 configuration_.enable_ice_renomination; | 1704 // Add audio/video/data m= sections to the end if needed. |
1715 | 1705 if (!audio_index && offer_new_audio_description) { |
1716 if (!ExtractMediaSessionOptions(rtc_options, true, session_options)) { | 1706 session_options->media_description_options.push_back( |
1717 return false; | 1707 cricket::MediaDescriptionOptions( |
1718 } | 1708 cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO, |
1719 | 1709 cricket::RtpTransceiverDirection(send_audio, recv_audio), false)); |
1720 AddSendStreams(session_options, senders_, rtp_data_channels_); | 1710 audio_index = rtc::Optional<size_t>( |
1721 // Offer to receive audio/video if the constraint is not set and there are | 1711 session_options->media_description_options.size() - 1); |
1722 // send streams, or we're currently receiving. | 1712 } |
1723 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) { | 1713 if (!video_index && offer_new_video_description) { |
1724 session_options->recv_audio = | 1714 session_options->media_description_options.push_back( |
1725 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) || | 1715 cricket::MediaDescriptionOptions( |
1726 !remote_audio_tracks_.empty(); | 1716 cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO, |
1727 } | 1717 cricket::RtpTransceiverDirection(send_video, recv_video), false)); |
1728 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) { | 1718 video_index = rtc::Optional<size_t>( |
1729 session_options->recv_video = | 1719 session_options->media_description_options.size() - 1); |
1730 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) || | 1720 } |
1731 !remote_video_tracks_.empty(); | 1721 if (!data_index && offer_new_data_description) { |
1732 } | 1722 session_options->media_description_options.push_back( |
| 1723 cricket::MediaDescriptionOptions( |
| 1724 cricket::MEDIA_TYPE_DATA, cricket::CN_DATA, |
| 1725 cricket::RtpTransceiverDirection(true, true), false)); |
| 1726 data_index = rtc::Optional<size_t>( |
| 1727 session_options->media_description_options.size() - 1); |
| 1728 } |
| 1729 |
| 1730 cricket::MediaDescriptionOptions* audio_media_description_options = |
| 1731 !audio_index ? nullptr |
| 1732 : &session_options->media_description_options[*audio_index]; |
| 1733 cricket::MediaDescriptionOptions* video_media_description_options = |
| 1734 !video_index ? nullptr |
| 1735 : &session_options->media_description_options[*video_index]; |
| 1736 cricket::MediaDescriptionOptions* data_media_description_options = |
| 1737 !data_index ? nullptr |
| 1738 : &session_options->media_description_options[*data_index]; |
| 1739 |
| 1740 // Apply ICE restart flag and renomination flag. |
| 1741 for (auto& options : session_options->media_description_options) { |
| 1742 options.transport_options.ice_restart = rtc_options.ice_restart; |
| 1743 options.transport_options.enable_ice_renomination = |
| 1744 configuration_.enable_ice_renomination; |
| 1745 } |
| 1746 |
| 1747 AddRtpSenderOptions(senders_, audio_media_description_options, |
| 1748 video_media_description_options); |
| 1749 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options); |
1733 | 1750 |
1734 // Intentionally unset the data channel type for RTP data channel with the | 1751 // Intentionally unset the data channel type for RTP data channel with the |
1735 // second condition. Otherwise the RTP data channels would be successfully | 1752 // second condition. Otherwise the RTP data channels would be successfully |
1736 // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail | 1753 // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail |
1737 // when building with chromium. We want to leave RTP data channels broken, so | 1754 // when building with chromium. We want to leave RTP data channels broken, so |
1738 // people won't try to use them. | 1755 // people won't try to use them. |
1739 if (HasDataChannels() && session_->data_channel_type() != cricket::DCT_RTP) { | 1756 if (!rtp_data_channels_.empty() || |
| 1757 session_->data_channel_type() != cricket::DCT_RTP) { |
1740 session_options->data_channel_type = session_->data_channel_type(); | 1758 session_options->data_channel_type = session_->data_channel_type(); |
1741 } | 1759 } |
1742 | 1760 |
1743 session_options->bundle_enabled = | |
1744 session_options->bundle_enabled && | |
1745 (session_options->has_audio() || session_options->has_video() || | |
1746 session_options->has_data()); | |
1747 | |
1748 session_options->rtcp_cname = rtcp_cname_; | 1761 session_options->rtcp_cname = rtcp_cname_; |
1749 session_options->crypto_options = factory_->options().crypto_options; | 1762 session_options->crypto_options = factory_->options().crypto_options; |
1750 return true; | 1763 } |
1751 } | 1764 |
1752 | 1765 void PeerConnection::GetOptionsForAnswer( |
1753 void PeerConnection::InitializeOptionsForAnswer( | 1766 const RTCOfferAnswerOptions& rtc_options, |
1754 cricket::MediaSessionOptions* session_options) { | 1767 cricket::MediaSessionOptions* session_options) { |
1755 session_options->recv_audio = false; | 1768 ExtractSharedMediaSessionOptions(rtc_options, session_options); |
1756 session_options->recv_video = false; | 1769 |
1757 session_options->enable_ice_renomination = | 1770 // Figure out transceiver directional preferences. |
1758 configuration_.enable_ice_renomination; | 1771 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO); |
1759 } | 1772 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO); |
1760 | 1773 |
1761 void PeerConnection::FinishOptionsForAnswer( | 1774 // By default, generate sendrecv/recvonly m= sections. The direction is also |
1762 cricket::MediaSessionOptions* session_options) { | 1775 // restricted by the direction in the offer. |
1763 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of | 1776 bool recv_audio = true; |
1764 // ContentInfos. | 1777 bool recv_video = true; |
1765 if (session_->remote_description()) { | 1778 |
1766 // Initialize the transport_options map. | 1779 // The "offer_to_receive_X" options allow those defaults to be overridden. |
1767 for (const cricket::ContentInfo& content : | 1780 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { |
1768 session_->remote_description()->description()->contents()) { | 1781 recv_audio = (rtc_options.offer_to_receive_audio > 0); |
1769 session_options->transport_options[content.name] = | 1782 } |
1770 cricket::TransportOptions(); | 1783 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { |
1771 } | 1784 recv_video = (rtc_options.offer_to_receive_video > 0); |
1772 } | 1785 } |
1773 AddSendStreams(session_options, senders_, rtp_data_channels_); | 1786 |
1774 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams | 1787 rtc::Optional<size_t> audio_index; |
1775 // are not signaled in the SDP so does not go through that path and must be | 1788 rtc::Optional<size_t> video_index; |
1776 // handled here. | 1789 rtc::Optional<size_t> data_index; |
| 1790 // There should be a pending remote description that's an offer... |
| 1791 RTC_DCHECK(session_->remote_description()); |
| 1792 RTC_DCHECK(session_->remote_description()->type() == |
| 1793 SessionDescriptionInterface::kOffer); |
| 1794 // Generate m= sections that match those in the offer. |
| 1795 // Note that mediasession.cc will handle intersection our preferred direction |
| 1796 // with the offered direction. |
| 1797 GenerateMediaDescriptionOptions( |
| 1798 session_->remote_description(), |
| 1799 cricket::RtpTransceiverDirection(send_audio, recv_audio), |
| 1800 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index, |
| 1801 &video_index, &data_index, session_options); |
| 1802 |
| 1803 cricket::MediaDescriptionOptions* audio_media_description_options = |
| 1804 !audio_index ? nullptr |
| 1805 : &session_options->media_description_options[*audio_index]; |
| 1806 cricket::MediaDescriptionOptions* video_media_description_options = |
| 1807 !video_index ? nullptr |
| 1808 : &session_options->media_description_options[*video_index]; |
| 1809 cricket::MediaDescriptionOptions* data_media_description_options = |
| 1810 !data_index ? nullptr |
| 1811 : &session_options->media_description_options[*data_index]; |
| 1812 |
| 1813 // Apply ICE renomination flag. |
| 1814 for (auto& options : session_options->media_description_options) { |
| 1815 options.transport_options.enable_ice_renomination = |
| 1816 configuration_.enable_ice_renomination; |
| 1817 } |
| 1818 |
| 1819 AddRtpSenderOptions(senders_, audio_media_description_options, |
| 1820 video_media_description_options); |
| 1821 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options); |
| 1822 |
1777 // Intentionally unset the data channel type for RTP data channel. Otherwise | 1823 // Intentionally unset the data channel type for RTP data channel. Otherwise |
1778 // the RTP data channels would be successfully negotiated by default and the | 1824 // the RTP data channels would be successfully negotiated by default and the |
1779 // unit tests in WebRtcDataBrowserTest will fail when building with chromium. | 1825 // unit tests in WebRtcDataBrowserTest will fail when building with chromium. |
1780 // We want to leave RTP data channels broken, so people won't try to use them. | 1826 // We want to leave RTP data channels broken, so people won't try to use them. |
1781 if (session_->data_channel_type() != cricket::DCT_RTP) { | 1827 if (!rtp_data_channels_.empty() || |
| 1828 session_->data_channel_type() != cricket::DCT_RTP) { |
1782 session_options->data_channel_type = session_->data_channel_type(); | 1829 session_options->data_channel_type = session_->data_channel_type(); |
1783 } | 1830 } |
1784 session_options->bundle_enabled = | 1831 |
1785 session_options->bundle_enabled && | 1832 session_options->rtcp_cname = rtcp_cname_; |
1786 (session_options->has_audio() || session_options->has_video() || | |
1787 session_options->has_data()); | |
1788 | |
1789 session_options->crypto_options = factory_->options().crypto_options; | 1833 session_options->crypto_options = factory_->options().crypto_options; |
1790 } | 1834 } |
1791 | 1835 |
1792 bool PeerConnection::GetOptionsForAnswer( | 1836 void PeerConnection::GenerateMediaDescriptionOptions( |
1793 const MediaConstraintsInterface* constraints, | 1837 const SessionDescriptionInterface* session_desc, |
| 1838 cricket::RtpTransceiverDirection audio_direction, |
| 1839 cricket::RtpTransceiverDirection video_direction, |
| 1840 rtc::Optional<size_t>* audio_index, |
| 1841 rtc::Optional<size_t>* video_index, |
| 1842 rtc::Optional<size_t>* data_index, |
1794 cricket::MediaSessionOptions* session_options) { | 1843 cricket::MediaSessionOptions* session_options) { |
1795 InitializeOptionsForAnswer(session_options); | 1844 for (const cricket::ContentInfo& content : |
1796 if (!ParseConstraintsForAnswer(constraints, session_options)) { | 1845 session_desc->description()->contents()) { |
1797 return false; | 1846 if (IsAudioContent(&content)) { |
1798 } | 1847 // If we already have an audio m= section, reject this extra one. |
1799 session_options->rtcp_cname = rtcp_cname_; | 1848 if (*audio_index) { |
1800 | 1849 session_options->media_description_options.push_back( |
1801 FinishOptionsForAnswer(session_options); | 1850 cricket::MediaDescriptionOptions( |
1802 return true; | 1851 cricket::MEDIA_TYPE_AUDIO, content.name, |
1803 } | 1852 cricket::RtpTransceiverDirection(false, false), true)); |
1804 | 1853 } else { |
1805 bool PeerConnection::GetOptionsForAnswer( | 1854 session_options->media_description_options.push_back( |
1806 const RTCOfferAnswerOptions& options, | 1855 cricket::MediaDescriptionOptions( |
1807 cricket::MediaSessionOptions* session_options) { | 1856 cricket::MEDIA_TYPE_AUDIO, content.name, audio_direction, |
1808 InitializeOptionsForAnswer(session_options); | 1857 !audio_direction.send && !audio_direction.recv)); |
1809 if (!ExtractMediaSessionOptions(options, false, session_options)) { | 1858 *audio_index = rtc::Optional<size_t>( |
1810 return false; | 1859 session_options->media_description_options.size() - 1); |
1811 } | 1860 } |
1812 session_options->rtcp_cname = rtcp_cname_; | 1861 } else if (IsVideoContent(&content)) { |
1813 | 1862 // If we already have an video m= section, reject this extra one. |
1814 FinishOptionsForAnswer(session_options); | 1863 if (*video_index) { |
1815 return true; | 1864 session_options->media_description_options.push_back( |
| 1865 cricket::MediaDescriptionOptions( |
| 1866 cricket::MEDIA_TYPE_VIDEO, content.name, |
| 1867 cricket::RtpTransceiverDirection(false, false), true)); |
| 1868 } else { |
| 1869 session_options->media_description_options.push_back( |
| 1870 cricket::MediaDescriptionOptions( |
| 1871 cricket::MEDIA_TYPE_VIDEO, content.name, video_direction, |
| 1872 !video_direction.send && !video_direction.recv)); |
| 1873 *video_index = rtc::Optional<size_t>( |
| 1874 session_options->media_description_options.size() - 1); |
| 1875 } |
| 1876 } else { |
| 1877 RTC_DCHECK(IsDataContent(&content)); |
| 1878 // If we already have an data m= section, reject this extra one. |
| 1879 if (*data_index) { |
| 1880 session_options->media_description_options.push_back( |
| 1881 cricket::MediaDescriptionOptions( |
| 1882 cricket::MEDIA_TYPE_DATA, content.name, |
| 1883 cricket::RtpTransceiverDirection(false, false), true)); |
| 1884 } else { |
| 1885 session_options->media_description_options.push_back( |
| 1886 cricket::MediaDescriptionOptions( |
| 1887 cricket::MEDIA_TYPE_DATA, content.name, |
| 1888 // Direction for data sections is meaningless, but legacy |
| 1889 // endpoints might expect sendrecv. |
| 1890 cricket::RtpTransceiverDirection(true, true), false)); |
| 1891 *data_index = rtc::Optional<size_t>( |
| 1892 session_options->media_description_options.size() - 1); |
| 1893 } |
| 1894 } |
| 1895 } |
1816 } | 1896 } |
1817 | 1897 |
1818 void PeerConnection::RemoveTracks(cricket::MediaType media_type) { | 1898 void PeerConnection::RemoveTracks(cricket::MediaType media_type) { |
1819 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type); | 1899 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type); |
1820 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false, | 1900 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false, |
1821 media_type, nullptr); | 1901 media_type, nullptr); |
1822 } | 1902 } |
1823 | 1903 |
1824 void PeerConnection::UpdateRemoteStreamsList( | 1904 void PeerConnection::UpdateRemoteStreamsList( |
1825 const cricket::StreamParamsVec& streams, | 1905 const cricket::StreamParamsVec& streams, |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2278 if (!channel.get()) { | 2358 if (!channel.get()) { |
2279 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."; | 2359 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."; |
2280 return; | 2360 return; |
2281 } | 2361 } |
2282 | 2362 |
2283 rtc::scoped_refptr<DataChannelInterface> proxy_channel = | 2363 rtc::scoped_refptr<DataChannelInterface> proxy_channel = |
2284 DataChannelProxy::Create(signaling_thread(), channel); | 2364 DataChannelProxy::Create(signaling_thread(), channel); |
2285 observer_->OnDataChannel(std::move(proxy_channel)); | 2365 observer_->OnDataChannel(std::move(proxy_channel)); |
2286 } | 2366 } |
2287 | 2367 |
| 2368 bool PeerConnection::HasRtpSender(cricket::MediaType type) const { |
| 2369 return std::find_if( |
| 2370 senders_.begin(), senders_.end(), |
| 2371 [type](const rtc::scoped_refptr< |
| 2372 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { |
| 2373 return sender->media_type() == type; |
| 2374 }) != senders_.end(); |
| 2375 } |
| 2376 |
2288 RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) { | 2377 RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) { |
2289 auto it = std::find_if( | 2378 auto it = std::find_if( |
2290 senders_.begin(), senders_.end(), | 2379 senders_.begin(), senders_.end(), |
2291 [id](const rtc::scoped_refptr< | 2380 [id](const rtc::scoped_refptr< |
2292 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { | 2381 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { |
2293 return sender->id() == id; | 2382 return sender->id() == id; |
2294 }); | 2383 }); |
2295 return it != senders_.end() ? (*it)->internal() : nullptr; | 2384 return it != senders_.end() ? (*it)->internal() : nullptr; |
2296 } | 2385 } |
2297 | 2386 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2434 return event_log_->StartLogging(file, max_size_bytes); | 2523 return event_log_->StartLogging(file, max_size_bytes); |
2435 } | 2524 } |
2436 | 2525 |
2437 void PeerConnection::StopRtcEventLog_w() { | 2526 void PeerConnection::StopRtcEventLog_w() { |
2438 if (event_log_) { | 2527 if (event_log_) { |
2439 event_log_->StopLogging(); | 2528 event_log_->StopLogging(); |
2440 } | 2529 } |
2441 } | 2530 } |
2442 | 2531 |
2443 } // namespace webrtc | 2532 } // namespace webrtc |
OLD | NEW |