diff --git a/pc/data_channel_controller.cc b/pc/data_channel_controller.cc index 9cbbc58fd8..ca50c346ff 100644 --- a/pc/data_channel_controller.cc +++ b/pc/data_channel_controller.cc @@ -28,6 +28,11 @@ bool DataChannelController::HasDataChannels() const { return !sctp_data_channels_.empty(); } +bool DataChannelController::HasUsedDataChannels() const { + RTC_DCHECK_RUN_ON(signaling_thread()); + return has_used_data_channels_; +} + bool DataChannelController::SendData(int sid, const SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, @@ -296,6 +301,7 @@ DataChannelController::InternalCreateSctpDataChannel( return nullptr; } sctp_data_channels_.push_back(channel); + has_used_data_channels_ = true; return channel; } diff --git a/pc/data_channel_controller.h b/pc/data_channel_controller.h index 8427656ec6..33c7463731 100644 --- a/pc/data_channel_controller.h +++ b/pc/data_channel_controller.h @@ -89,7 +89,10 @@ class DataChannelController : public SctpDataChannelControllerInterface, void AllocateSctpSids(rtc::SSLRole role); // Checks if any data channel has been added. + // A data channel currently exist. bool HasDataChannels() const; + // At some point in time, a data channel has existed. + bool HasUsedDataChannels() const; bool HasSctpDataChannels() const { RTC_DCHECK_RUN_ON(signaling_thread()); return !sctp_data_channels_.empty(); @@ -148,6 +151,7 @@ class DataChannelController : public SctpDataChannelControllerInterface, SctpSidAllocator sid_allocator_ /* RTC_GUARDED_BY(signaling_thread()) */; std::vector> sctp_data_channels_ RTC_GUARDED_BY(signaling_thread()); + bool has_used_data_channels_ RTC_GUARDED_BY(signaling_thread()) = false; // Owning PeerConnection. PeerConnectionInternal* const pc_; diff --git a/pc/data_channel_controller_unittest.cc b/pc/data_channel_controller_unittest.cc index 0d9dd88efd..0f840e7f34 100644 --- a/pc/data_channel_controller_unittest.cc +++ b/pc/data_channel_controller_unittest.cc @@ -70,6 +70,20 @@ TEST_F(DataChannelControllerTest, CreateDataChannelEarlyRelease) { channel = nullptr; // dcc holds a reference to channel, so not destroyed yet } +TEST_F(DataChannelControllerTest, CreateDataChannelEarlyClose) { + DataChannelController dcc(pc_.get()); + EXPECT_FALSE(dcc.HasDataChannels()); + EXPECT_FALSE(dcc.HasUsedDataChannels()); + auto channel = dcc.InternalCreateDataChannelWithProxy( + "label", + std::make_unique(DataChannelInit()).get()); + EXPECT_TRUE(dcc.HasDataChannels()); + EXPECT_TRUE(dcc.HasUsedDataChannels()); + channel->Close(); + EXPECT_FALSE(dcc.HasDataChannels()); + EXPECT_TRUE(dcc.HasUsedDataChannels()); +} + TEST_F(DataChannelControllerTest, CreateDataChannelLateRelease) { auto dcc = std::make_unique(pc_.get()); auto channel = dcc->InternalCreateDataChannelWithProxy( diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index ca234f74a1..a6272f505b 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -1393,7 +1393,7 @@ PeerConnection::CreateDataChannelOrError(const std::string& label, RTC_DCHECK_RUN_ON(signaling_thread()); TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel"); - bool first_datachannel = !data_channel_controller_.HasDataChannels(); + bool first_datachannel = !data_channel_controller_.HasUsedDataChannels(); std::unique_ptr internal_config; if (config) { diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc index 33e6e7a3a0..0b4183f86c 100644 --- a/pc/sdp_offer_answer.cc +++ b/pc/sdp_offer_answer.cc @@ -3955,7 +3955,7 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer( const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options, cricket::MediaSessionOptions* session_options) { bool offer_new_data_description = - data_channel_controller()->HasDataChannels(); + data_channel_controller()->HasUsedDataChannels(); bool send_audio = false; bool send_video = false; bool recv_audio = false; @@ -4172,9 +4172,9 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( transceiver->set_mline_index(mline_index); } } - // Lastly, add a m-section if we have local data channels and an m section - // does not already exist. - if (!pc_->GetDataMid() && data_channel_controller()->HasDataChannels()) { + // Lastly, add a m-section if we have requested local data channels and an + // m section does not already exist. + if (!pc_->GetDataMid() && data_channel_controller()->HasUsedDataChannels()) { session_options->media_description_options.push_back( GetMediaDescriptionOptionsForActiveData( mid_generator_.GenerateString()));