Chromium Code Reviews| 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 |