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; |
846 | 829 if (!ConvertConstraintsToOfferAnswerOptions(constraints, |
847 bool value; | 830 &offer_answer_options)) { |
848 size_t mandatory_constraints = 0; | 831 std::string error = "CreateOffer called with invalid constraints."; |
849 | 832 LOG(LS_ERROR) << error; |
850 if (FindConstraint(constraints, | 833 PostCreateSessionDescriptionFailure(observer, error); |
851 MediaConstraintsInterface::kOfferToReceiveAudio, | 834 return; |
852 &value, | |
853 &mandatory_constraints)) { | |
854 options.offer_to_receive_audio = | |
855 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0; | |
856 } | 835 } |
857 | 836 |
858 if (FindConstraint(constraints, | 837 CreateOffer(observer, offer_answer_options); |
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 } | 838 } |
889 | 839 |
890 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, | 840 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, |
891 const RTCOfferAnswerOptions& options) { | 841 const RTCOfferAnswerOptions& options) { |
892 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); | 842 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer"); |
893 if (!observer) { | 843 if (!observer) { |
894 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; | 844 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; |
895 return; | 845 return; |
896 } | 846 } |
897 | 847 |
898 cricket::MediaSessionOptions session_options; | 848 if (!ValidateOfferAnswerOptions(options)) { |
899 if (!GetOptionsForOffer(options, &session_options)) { | |
900 std::string error = "CreateOffer called with invalid options."; | 849 std::string error = "CreateOffer called with invalid options."; |
901 LOG(LS_ERROR) << error; | 850 LOG(LS_ERROR) << error; |
902 PostCreateSessionDescriptionFailure(observer, error); | 851 PostCreateSessionDescriptionFailure(observer, error); |
903 return; | 852 return; |
904 } | 853 } |
905 | 854 |
855 cricket::MediaSessionOptions session_options; | |
856 GetOptionsForOffer(options, &session_options); | |
906 session_->CreateOffer(observer, options, session_options); | 857 session_->CreateOffer(observer, options, session_options); |
907 } | 858 } |
908 | 859 |
909 void PeerConnection::CreateAnswer( | 860 void PeerConnection::CreateAnswer( |
910 CreateSessionDescriptionObserver* observer, | 861 CreateSessionDescriptionObserver* observer, |
911 const MediaConstraintsInterface* constraints) { | 862 const MediaConstraintsInterface* constraints) { |
912 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); | 863 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); |
913 if (!observer) { | 864 if (!observer) { |
914 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; | 865 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; |
915 return; | 866 return; |
916 } | 867 } |
917 | 868 |
918 cricket::MediaSessionOptions session_options; | 869 if (!session_->remote_description() || |
919 if (!GetOptionsForAnswer(constraints, &session_options)) { | 870 session_->remote_description()->type() != |
871 SessionDescriptionInterface::kOffer) { | |
872 std::string error = "CreateAnswer called without remote offer."; | |
873 LOG(LS_ERROR) << error; | |
874 PostCreateSessionDescriptionFailure(observer, error); | |
875 return; | |
876 } | |
877 | |
878 PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options; | |
879 if (!ConvertConstraintsToOfferAnswerOptions(constraints, | |
880 &offer_answer_options)) { | |
920 std::string error = "CreateAnswer called with invalid constraints."; | 881 std::string error = "CreateAnswer called with invalid constraints."; |
921 LOG(LS_ERROR) << error; | 882 LOG(LS_ERROR) << error; |
922 PostCreateSessionDescriptionFailure(observer, error); | 883 PostCreateSessionDescriptionFailure(observer, error); |
923 return; | 884 return; |
924 } | 885 } |
925 | 886 |
887 cricket::MediaSessionOptions session_options; | |
888 GetOptionsForAnswer(offer_answer_options, &session_options); | |
926 session_->CreateAnswer(observer, session_options); | 889 session_->CreateAnswer(observer, session_options); |
927 } | 890 } |
928 | 891 |
929 void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer, | 892 void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer, |
930 const RTCOfferAnswerOptions& options) { | 893 const RTCOfferAnswerOptions& options) { |
931 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); | 894 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer"); |
932 if (!observer) { | 895 if (!observer) { |
933 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; | 896 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; |
934 return; | 897 return; |
935 } | 898 } |
936 | 899 |
937 cricket::MediaSessionOptions session_options; | 900 cricket::MediaSessionOptions session_options; |
938 if (!GetOptionsForAnswer(options, &session_options)) { | 901 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 | 902 |
945 session_->CreateAnswer(observer, session_options); | 903 session_->CreateAnswer(observer, session_options); |
946 } | 904 } |
947 | 905 |
948 void PeerConnection::SetLocalDescription( | 906 void PeerConnection::SetLocalDescription( |
949 SetSessionDescriptionObserver* observer, | 907 SetSessionDescriptionObserver* observer, |
950 SessionDescriptionInterface* desc) { | 908 SessionDescriptionInterface* desc) { |
951 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription"); | 909 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription"); |
952 if (IsClosed()) { | 910 if (IsClosed()) { |
953 return; | 911 return; |
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1691 | 1649 |
1692 void PeerConnection::PostCreateSessionDescriptionFailure( | 1650 void PeerConnection::PostCreateSessionDescriptionFailure( |
1693 CreateSessionDescriptionObserver* observer, | 1651 CreateSessionDescriptionObserver* observer, |
1694 const std::string& error) { | 1652 const std::string& error) { |
1695 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | 1653 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); |
1696 msg->error = error; | 1654 msg->error = error; |
1697 signaling_thread()->Post(RTC_FROM_HERE, this, | 1655 signaling_thread()->Post(RTC_FROM_HERE, this, |
1698 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); | 1656 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); |
1699 } | 1657 } |
1700 | 1658 |
1701 bool PeerConnection::GetOptionsForOffer( | 1659 void PeerConnection::GetOptionsForOffer( |
1702 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, | 1660 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, |
1703 cricket::MediaSessionOptions* session_options) { | 1661 cricket::MediaSessionOptions* session_options) { |
1704 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of | 1662 ExtractSharedMediaSessionOptions(rtc_options, session_options); |
1705 // ContentInfos. | 1663 |
1706 if (session_->local_description()) { | 1664 // Figure out transceiver directional preferences. |
1707 for (const cricket::ContentInfo& content : | 1665 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO); |
1708 session_->local_description()->description()->contents()) { | 1666 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO); |
1709 session_options->transport_options[content.name] = | 1667 |
1710 cricket::TransportOptions(); | 1668 // By default, generate sendrecv/recvonly m= sections. |
1711 } | 1669 bool recv_audio = true; |
1670 bool recv_video = true; | |
1671 | |
1672 // By default, only offer a new m= section if we have media to send with it. | |
1673 bool offer_new_audio_description = send_audio; | |
1674 bool offer_new_video_description = send_video; | |
1675 bool offer_new_data_description = HasDataChannels(); | |
1676 | |
1677 // The "offer_to_receive_X" options allow those defaults to be overridden. | |
1678 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { | |
1679 recv_audio = (rtc_options.offer_to_receive_audio > 0); | |
1680 offer_new_audio_description = (rtc_options.offer_to_receive_audio > 0); | |
1712 } | 1681 } |
1713 session_options->enable_ice_renomination = | 1682 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { |
1714 configuration_.enable_ice_renomination; | 1683 recv_video = (rtc_options.offer_to_receive_video > 0); |
1715 | 1684 offer_new_video_description = (rtc_options.offer_to_receive_video > 0); |
1716 if (!ExtractMediaSessionOptions(rtc_options, true, session_options)) { | |
1717 return false; | |
1718 } | 1685 } |
1719 | 1686 |
1720 AddSendStreams(session_options, senders_, rtp_data_channels_); | 1687 int audio_index = -1; |
1721 // Offer to receive audio/video if the constraint is not set and there are | 1688 int video_index = -1; |
1722 // send streams, or we're currently receiving. | 1689 int data_index = -1; |
1723 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) { | 1690 // If a current description exists, generate m= sections in the same order, |
1724 session_options->recv_audio = | 1691 // using the first audio/video/data section that appears and rejecting |
1725 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) || | 1692 // extraneous ones. |
1726 !remote_audio_tracks_.empty(); | 1693 if (session_->local_description()) { |
1694 GenerateMediaDescrptionOptions( | |
Taylor Brandstetter
2017/08/03 00:24:48
nit: "Description" is missing an "i".
Zhi Huang
2017/08/04 18:38:25
Done.
| |
1695 session_->local_description(), | |
1696 cricket::RtpTransceiverDirection(send_audio, recv_audio), | |
1697 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index, | |
1698 &video_index, &data_index, session_options); | |
1727 } | 1699 } |
1728 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) { | 1700 |
1729 session_options->recv_video = | 1701 // Add audio/video/data m= sections to the end if needed. |
1730 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) || | 1702 if (audio_index == -1 && offer_new_audio_description) { |
1731 !remote_video_tracks_.empty(); | 1703 session_options->media_description_options.push_back( |
1704 cricket::MediaDescriptionOptions( | |
1705 cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO, | |
1706 cricket::RtpTransceiverDirection(send_audio, recv_audio), false)); | |
1707 audio_index = session_options->media_description_options.size() - 1; | |
1732 } | 1708 } |
1709 if (video_index == -1 && offer_new_video_description) { | |
1710 session_options->media_description_options.push_back( | |
1711 cricket::MediaDescriptionOptions( | |
1712 cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO, | |
1713 cricket::RtpTransceiverDirection(send_video, recv_video), false)); | |
1714 video_index = session_options->media_description_options.size() - 1; | |
1715 } | |
1716 if (data_index == -1 && offer_new_data_description) { | |
1717 session_options->media_description_options.push_back( | |
1718 cricket::MediaDescriptionOptions( | |
1719 cricket::MEDIA_TYPE_DATA, cricket::CN_DATA, | |
1720 cricket::RtpTransceiverDirection(true, true), false)); | |
1721 data_index = session_options->media_description_options.size() - 1; | |
1722 } | |
1723 | |
1724 cricket::MediaDescriptionOptions* audio_media_description_options = | |
1725 audio_index == -1 | |
1726 ? nullptr | |
1727 : &session_options->media_description_options[audio_index]; | |
1728 cricket::MediaDescriptionOptions* video_media_description_options = | |
1729 video_index == -1 | |
1730 ? nullptr | |
1731 : &session_options->media_description_options[video_index]; | |
1732 cricket::MediaDescriptionOptions* data_media_description_options = | |
1733 data_index == -1 | |
1734 ? nullptr | |
1735 : &session_options->media_description_options[data_index]; | |
1736 | |
1737 // Apply ICE restart flag and renomination flag. | |
1738 for (auto& options : session_options->media_description_options) { | |
1739 options.transport_options.ice_restart = rtc_options.ice_restart; | |
1740 options.transport_options.enable_ice_renomination = | |
1741 configuration_.enable_ice_renomination; | |
1742 } | |
1743 | |
1744 AddRtpSenderOptions(senders_, audio_media_description_options, | |
1745 video_media_description_options); | |
1746 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options); | |
1733 | 1747 |
1734 // Intentionally unset the data channel type for RTP data channel with the | 1748 // Intentionally unset the data channel type for RTP data channel with the |
1735 // second condition. Otherwise the RTP data channels would be successfully | 1749 // second condition. Otherwise the RTP data channels would be successfully |
1736 // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail | 1750 // 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 | 1751 // when building with chromium. We want to leave RTP data channels broken, so |
1738 // people won't try to use them. | 1752 // people won't try to use them. |
1739 if (HasDataChannels() && session_->data_channel_type() != cricket::DCT_RTP) { | 1753 if (session_->data_channel_type() != cricket::DCT_RTP) { |
1740 session_options->data_channel_type = session_->data_channel_type(); | 1754 session_options->data_channel_type = session_->data_channel_type(); |
1741 } | 1755 } |
1742 | 1756 |
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_; | 1757 session_options->rtcp_cname = rtcp_cname_; |
1749 session_options->crypto_options = factory_->options().crypto_options; | 1758 session_options->crypto_options = factory_->options().crypto_options; |
1750 return true; | |
1751 } | 1759 } |
1752 | 1760 |
1753 void PeerConnection::InitializeOptionsForAnswer( | 1761 void PeerConnection::GetOptionsForAnswer( |
1762 const RTCOfferAnswerOptions& rtc_options, | |
1754 cricket::MediaSessionOptions* session_options) { | 1763 cricket::MediaSessionOptions* session_options) { |
1755 session_options->recv_audio = false; | 1764 ExtractSharedMediaSessionOptions(rtc_options, session_options); |
1756 session_options->recv_video = false; | |
1757 session_options->enable_ice_renomination = | |
1758 configuration_.enable_ice_renomination; | |
1759 } | |
1760 | 1765 |
1761 void PeerConnection::FinishOptionsForAnswer( | 1766 // Figure out transceiver directional preferences. |
1762 cricket::MediaSessionOptions* session_options) { | 1767 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO); |
1763 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of | 1768 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO); |
1764 // ContentInfos. | 1769 |
1765 if (session_->remote_description()) { | 1770 // By default, generate sendrecv/recvonly m= sections. The direction is also |
1766 // Initialize the transport_options map. | 1771 // restricted by the direction in the offer. |
1767 for (const cricket::ContentInfo& content : | 1772 bool recv_audio = true; |
1768 session_->remote_description()->description()->contents()) { | 1773 bool recv_video = true; |
1769 session_options->transport_options[content.name] = | 1774 |
1770 cricket::TransportOptions(); | 1775 // The "offer_to_receive_X" options allow those defaults to be overridden. |
1771 } | 1776 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) { |
1777 recv_audio = (rtc_options.offer_to_receive_audio > 0); | |
1772 } | 1778 } |
1773 AddSendStreams(session_options, senders_, rtp_data_channels_); | 1779 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) { |
1774 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams | 1780 recv_video = (rtc_options.offer_to_receive_video > 0); |
1775 // are not signaled in the SDP so does not go through that path and must be | 1781 } |
1776 // handled here. | 1782 |
1783 int audio_index = -1; | |
1784 int video_index = -1; | |
1785 int data_index = -1; | |
1786 // There should be a pending remote description that's an offer... | |
1787 RTC_DCHECK(session_->remote_description()); | |
1788 RTC_DCHECK(session_->remote_description()->type() == | |
1789 SessionDescriptionInterface::kOffer); | |
1790 // Generate m= sections that match those in the offer. | |
1791 // Note that mediasession.cc will handle intersection our preferred direction | |
1792 // with the offered direction. | |
1793 GenerateMediaDescrptionOptions( | |
1794 session_->remote_description(), | |
1795 cricket::RtpTransceiverDirection(send_audio, recv_audio), | |
1796 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index, | |
1797 &video_index, &data_index, session_options); | |
1798 | |
1799 cricket::MediaDescriptionOptions* audio_media_description_options = | |
1800 audio_index == -1 | |
1801 ? nullptr | |
1802 : &session_options->media_description_options[audio_index]; | |
1803 cricket::MediaDescriptionOptions* video_media_description_options = | |
1804 video_index == -1 | |
1805 ? nullptr | |
1806 : &session_options->media_description_options[video_index]; | |
1807 cricket::MediaDescriptionOptions* data_media_description_options = | |
1808 data_index == -1 | |
1809 ? nullptr | |
1810 : &session_options->media_description_options[data_index]; | |
1811 | |
1812 // Apply ICE renomination flag. | |
1813 for (auto& options : session_options->media_description_options) { | |
1814 options.transport_options.enable_ice_renomination = | |
1815 configuration_.enable_ice_renomination; | |
1816 } | |
1817 | |
1818 AddRtpSenderOptions(senders_, audio_media_description_options, | |
1819 video_media_description_options); | |
1820 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options); | |
1821 | |
1777 // Intentionally unset the data channel type for RTP data channel. Otherwise | 1822 // Intentionally unset the data channel type for RTP data channel. Otherwise |
1778 // the RTP data channels would be successfully negotiated by default and the | 1823 // the RTP data channels would be successfully negotiated by default and the |
1779 // unit tests in WebRtcDataBrowserTest will fail when building with chromium. | 1824 // 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. | 1825 // 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) { | 1826 if (session_->data_channel_type() != cricket::DCT_RTP) { |
1782 session_options->data_channel_type = session_->data_channel_type(); | 1827 session_options->data_channel_type = session_->data_channel_type(); |
1783 } | 1828 } |
1784 session_options->bundle_enabled = | 1829 session_options->rtcp_cname = rtcp_cname_; |
1785 session_options->bundle_enabled && | |
1786 (session_options->has_audio() || session_options->has_video() || | |
1787 session_options->has_data()); | |
1788 | |
1789 session_options->crypto_options = factory_->options().crypto_options; | 1830 session_options->crypto_options = factory_->options().crypto_options; |
1790 } | 1831 } |
1791 | 1832 |
1792 bool PeerConnection::GetOptionsForAnswer( | 1833 void PeerConnection::GenerateMediaDescrptionOptions( |
1793 const MediaConstraintsInterface* constraints, | 1834 const SessionDescriptionInterface* session_desc, |
1835 cricket::RtpTransceiverDirection audio_direction, | |
1836 cricket::RtpTransceiverDirection video_direction, | |
1837 int* audio_index, | |
1838 int* video_index, | |
1839 int* data_index, | |
1794 cricket::MediaSessionOptions* session_options) { | 1840 cricket::MediaSessionOptions* session_options) { |
1795 InitializeOptionsForAnswer(session_options); | 1841 for (const cricket::ContentInfo& content : |
1796 if (!ParseConstraintsForAnswer(constraints, session_options)) { | 1842 session_desc->description()->contents()) { |
1797 return false; | 1843 if (IsAudioContent(&content)) { |
1844 // If we already have an audio m= section, reject this extra one. | |
1845 if (*audio_index != -1) { | |
1846 session_options->media_description_options.push_back( | |
1847 cricket::MediaDescriptionOptions( | |
1848 cricket::MEDIA_TYPE_AUDIO, content.name, | |
1849 cricket::RtpTransceiverDirection(false, false), true)); | |
1850 } else { | |
1851 session_options->media_description_options.push_back( | |
1852 cricket::MediaDescriptionOptions( | |
1853 cricket::MEDIA_TYPE_AUDIO, content.name, audio_direction, | |
1854 !audio_direction.send && !audio_direction.recv)); | |
1855 *audio_index = session_options->media_description_options.size() - 1; | |
1856 } | |
1857 } else if (IsVideoContent(&content)) { | |
1858 // If we already have an video m= section, reject this extra one. | |
1859 if (*video_index != -1) { | |
1860 session_options->media_description_options.push_back( | |
1861 cricket::MediaDescriptionOptions( | |
1862 cricket::MEDIA_TYPE_VIDEO, content.name, | |
1863 cricket::RtpTransceiverDirection(false, false), true)); | |
1864 } else { | |
1865 session_options->media_description_options.push_back( | |
1866 cricket::MediaDescriptionOptions( | |
1867 cricket::MEDIA_TYPE_VIDEO, content.name, video_direction, | |
1868 !video_direction.send && !video_direction.recv)); | |
1869 *video_index = session_options->media_description_options.size() - 1; | |
1870 } | |
1871 } else { | |
1872 RTC_DCHECK(IsDataContent(&content)); | |
1873 // If we already have an data m= section, reject this extra one. | |
1874 if (*data_index != -1) { | |
1875 session_options->media_description_options.push_back( | |
1876 cricket::MediaDescriptionOptions( | |
1877 cricket::MEDIA_TYPE_DATA, content.name, | |
1878 cricket::RtpTransceiverDirection(false, false), true)); | |
1879 } else { | |
1880 session_options->media_description_options.push_back( | |
1881 cricket::MediaDescriptionOptions( | |
1882 cricket::MEDIA_TYPE_DATA, content.name, | |
1883 // Direction for data sections is meaningless, but legacy | |
1884 // endpoints might expect sendrecv. | |
1885 cricket::RtpTransceiverDirection(true, true), false)); | |
1886 *data_index = session_options->media_description_options.size() - 1; | |
1887 } | |
1888 } | |
1798 } | 1889 } |
1799 session_options->rtcp_cname = rtcp_cname_; | |
1800 | |
1801 FinishOptionsForAnswer(session_options); | |
1802 return true; | |
1803 } | |
1804 | |
1805 bool PeerConnection::GetOptionsForAnswer( | |
1806 const RTCOfferAnswerOptions& options, | |
1807 cricket::MediaSessionOptions* session_options) { | |
1808 InitializeOptionsForAnswer(session_options); | |
1809 if (!ExtractMediaSessionOptions(options, false, session_options)) { | |
1810 return false; | |
1811 } | |
1812 session_options->rtcp_cname = rtcp_cname_; | |
1813 | |
1814 FinishOptionsForAnswer(session_options); | |
1815 return true; | |
1816 } | 1890 } |
1817 | 1891 |
1818 void PeerConnection::RemoveTracks(cricket::MediaType media_type) { | 1892 void PeerConnection::RemoveTracks(cricket::MediaType media_type) { |
1819 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type); | 1893 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type); |
1820 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false, | 1894 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false, |
1821 media_type, nullptr); | 1895 media_type, nullptr); |
1822 } | 1896 } |
1823 | 1897 |
1824 void PeerConnection::UpdateRemoteStreamsList( | 1898 void PeerConnection::UpdateRemoteStreamsList( |
1825 const cricket::StreamParamsVec& streams, | 1899 const cricket::StreamParamsVec& streams, |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2278 if (!channel.get()) { | 2352 if (!channel.get()) { |
2279 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."; | 2353 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."; |
2280 return; | 2354 return; |
2281 } | 2355 } |
2282 | 2356 |
2283 rtc::scoped_refptr<DataChannelInterface> proxy_channel = | 2357 rtc::scoped_refptr<DataChannelInterface> proxy_channel = |
2284 DataChannelProxy::Create(signaling_thread(), channel); | 2358 DataChannelProxy::Create(signaling_thread(), channel); |
2285 observer_->OnDataChannel(std::move(proxy_channel)); | 2359 observer_->OnDataChannel(std::move(proxy_channel)); |
2286 } | 2360 } |
2287 | 2361 |
2362 bool PeerConnection::HasRtpSender(cricket::MediaType type) const { | |
2363 return std::find_if( | |
2364 senders_.begin(), senders_.end(), | |
2365 [type](const rtc::scoped_refptr< | |
2366 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { | |
2367 return sender->media_type() == type; | |
2368 }) != senders_.end(); | |
2369 } | |
2370 | |
2288 RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) { | 2371 RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) { |
2289 auto it = std::find_if( | 2372 auto it = std::find_if( |
2290 senders_.begin(), senders_.end(), | 2373 senders_.begin(), senders_.end(), |
2291 [id](const rtc::scoped_refptr< | 2374 [id](const rtc::scoped_refptr< |
2292 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { | 2375 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) { |
2293 return sender->id() == id; | 2376 return sender->id() == id; |
2294 }); | 2377 }); |
2295 return it != senders_.end() ? (*it)->internal() : nullptr; | 2378 return it != senders_.end() ? (*it)->internal() : nullptr; |
2296 } | 2379 } |
2297 | 2380 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2434 return event_log_->StartLogging(file, max_size_bytes); | 2517 return event_log_->StartLogging(file, max_size_bytes); |
2435 } | 2518 } |
2436 | 2519 |
2437 void PeerConnection::StopRtcEventLog_w() { | 2520 void PeerConnection::StopRtcEventLog_w() { |
2438 if (event_log_) { | 2521 if (event_log_) { |
2439 event_log_->StopLogging(); | 2522 event_log_->StopLogging(); |
2440 } | 2523 } |
2441 } | 2524 } |
2442 | 2525 |
2443 } // namespace webrtc | 2526 } // namespace webrtc |
OLD | NEW |