mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00
Make negotiationneeded processing in PeerConnection spec compliant.
This CL fixes the problem of misfired negotiationneeded notifications due to the lack of a NegotiationNeeded slot and the proper procedure to update it. Change-Id: Ie273c691f11316c9846606446f6cf838226b5d5c Bug: chromium:740501 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/131283 Commit-Queue: Guido Urdaneta <guidou@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Magnus Jedvert <magjed@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27594}
This commit is contained in:
parent
16cb8f5d74
commit
1fa06041bc
7 changed files with 289 additions and 26 deletions
|
@ -698,6 +698,15 @@ void ReportSimulcastApiVersion(const char* name,
|
|||
}
|
||||
}
|
||||
|
||||
const ContentInfo* FindTransceiverMSection(
|
||||
RtpTransceiverProxyWithInternal<RtpTransceiver>* transceiver,
|
||||
const SessionDescriptionInterface* session_description) {
|
||||
return transceiver->mid()
|
||||
? session_description->description()->GetContentByName(
|
||||
*transceiver->mid())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Upon completion, posts a task to execute the callback of the
|
||||
|
@ -1254,7 +1263,7 @@ bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
|
|||
}
|
||||
|
||||
stats_->AddStream(local_stream);
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1284,7 +1293,7 @@ void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
|
|||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
|
||||
|
@ -1313,7 +1322,7 @@ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
|
|||
(IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
|
||||
: AddTrackPlanB(track, stream_ids));
|
||||
if (sender_or_error.ok()) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
stats_->AddTrack(track);
|
||||
}
|
||||
return sender_or_error;
|
||||
|
@ -1460,7 +1469,7 @@ RTCError PeerConnection::RemoveTrackNew(
|
|||
"Couldn't find sender " + sender->id() + " to remove.");
|
||||
}
|
||||
}
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1536,7 @@ PeerConnection::AddTransceiver(
|
|||
cricket::MediaType media_type,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const RtpTransceiverInit& init,
|
||||
bool fire_callback) {
|
||||
bool update_negotiation_needed) {
|
||||
RTC_DCHECK((media_type == cricket::MEDIA_TYPE_AUDIO ||
|
||||
media_type == cricket::MEDIA_TYPE_VIDEO));
|
||||
if (track) {
|
||||
|
@ -1616,8 +1625,8 @@ PeerConnection::AddTransceiver(
|
|||
auto transceiver = CreateAndAddTransceiver(sender, receiver);
|
||||
transceiver->internal()->set_direction(init.direction);
|
||||
|
||||
if (fire_callback) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
if (update_negotiation_needed) {
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
return rtc::scoped_refptr<RtpTransceiverInterface>(transceiver);
|
||||
|
@ -1695,7 +1704,7 @@ PeerConnection::CreateAndAddTransceiver(
|
|||
void PeerConnection::OnNegotiationNeeded() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(!IsClosed());
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
|
||||
|
@ -1943,7 +1952,7 @@ rtc::scoped_refptr<DataChannelInterface> PeerConnection::CreateDataChannel(
|
|||
// Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
|
||||
// the first SCTP DataChannel.
|
||||
if (data_channel_type() == cricket::DCT_RTP || first_datachannel) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
NoteUsageEvent(UsageEvent::DATA_ADDED);
|
||||
return DataChannelProxy::Create(signaling_thread(), channel.get());
|
||||
|
@ -2045,7 +2054,8 @@ void PeerConnection::AddUpToOneReceivingTransceiverOfType(
|
|||
<< " transceiver since CreateOffer specified offer_to_receive=1";
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kRecvOnly;
|
||||
AddTransceiver(media_type, nullptr, init, /*fire_callback=*/false);
|
||||
AddTransceiver(media_type, nullptr, init,
|
||||
/*update_negotiation_needed=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2189,6 +2199,14 @@ void PeerConnection::SetLocalDescription(
|
|||
// Make UMA notes about what was agreed to.
|
||||
ReportNegotiatedSdpSemantics(*local_description());
|
||||
}
|
||||
|
||||
bool was_negotiation_needed = is_negotiation_needed_;
|
||||
UpdateNegotiationNeeded();
|
||||
if (signaling_state() == kStable && was_negotiation_needed &&
|
||||
is_negotiation_needed_) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
}
|
||||
|
||||
NoteUsageEvent(UsageEvent::SET_LOCAL_DESCRIPTION_CALLED);
|
||||
}
|
||||
|
||||
|
@ -2546,6 +2564,13 @@ void PeerConnection::SetRemoteDescription(
|
|||
ReportNegotiatedSdpSemantics(*remote_description());
|
||||
}
|
||||
|
||||
bool was_negotiation_needed = is_negotiation_needed_;
|
||||
UpdateNegotiationNeeded();
|
||||
if (signaling_state() == kStable && was_negotiation_needed &&
|
||||
is_negotiation_needed_) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
}
|
||||
|
||||
observer->OnSetRemoteDescriptionComplete(RTCError::OK());
|
||||
NoteUsageEvent(UsageEvent::SET_REMOTE_DESCRIPTION_CALLED);
|
||||
}
|
||||
|
@ -4158,7 +4183,7 @@ void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
|
|||
return;
|
||||
}
|
||||
AddAudioTrack(track, stream);
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
|
||||
|
@ -4167,7 +4192,7 @@ void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
|
|||
return;
|
||||
}
|
||||
RemoveAudioTrack(track, stream);
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
|
||||
|
@ -4176,7 +4201,7 @@ void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
|
|||
return;
|
||||
}
|
||||
AddVideoTrack(track, stream);
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
|
||||
|
@ -4185,7 +4210,7 @@ void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
|
|||
return;
|
||||
}
|
||||
RemoveVideoTrack(track, stream);
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
UpdateNegotiationNeeded();
|
||||
}
|
||||
|
||||
void PeerConnection::PostSetSessionDescriptionSuccess(
|
||||
|
@ -7125,4 +7150,169 @@ void PeerConnection::RequestUsagePatternReportForTesting() {
|
|||
nullptr);
|
||||
}
|
||||
|
||||
void PeerConnection::UpdateNegotiationNeeded() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
// If connection's [[IsClosed]] slot is true, abort these steps.
|
||||
if (IsClosed())
|
||||
return;
|
||||
|
||||
// If connection's signaling state is not "stable", abort these steps.
|
||||
if (signaling_state() != kStable)
|
||||
return;
|
||||
|
||||
// NOTE
|
||||
// The negotiation-needed flag will be updated once the state transitions to
|
||||
// "stable", as part of the steps for setting an RTCSessionDescription.
|
||||
|
||||
// If the result of checking if negotiation is needed is false, clear the
|
||||
// negotiation-needed flag by setting connection's [[NegotiationNeeded]] slot
|
||||
// to false, and abort these steps.
|
||||
bool is_negotiation_needed = CheckIfNegotiationIsNeeded();
|
||||
if (!is_negotiation_needed) {
|
||||
is_negotiation_needed_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// If connection's [[NegotiationNeeded]] slot is already true, abort these
|
||||
// steps.
|
||||
if (is_negotiation_needed_)
|
||||
return;
|
||||
|
||||
// Set connection's [[NegotiationNeeded]] slot to true.
|
||||
is_negotiation_needed_ = true;
|
||||
|
||||
// Queue a task that runs the following steps:
|
||||
// If connection's [[IsClosed]] slot is true, abort these steps.
|
||||
// If connection's [[NegotiationNeeded]] slot is false, abort these steps.
|
||||
// Fire an event named negotiationneeded at connection.
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
}
|
||||
|
||||
bool PeerConnection::CheckIfNegotiationIsNeeded() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
// 1. If any implementation-specific negotiation is required, as described at
|
||||
// the start of this section, return true.
|
||||
|
||||
// 2. Let description be connection.[[CurrentLocalDescription]].
|
||||
const SessionDescriptionInterface* description = current_local_description();
|
||||
if (!description)
|
||||
return true;
|
||||
|
||||
// 3. If connection has created any RTCDataChannels, and no m= section in
|
||||
// description has been negotiated yet for data, return true.
|
||||
if (!sctp_data_channels_.empty()) {
|
||||
if (!cricket::GetFirstDataContent(description->description()->contents()))
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. For each transceiver in connection's set of transceivers, perform the
|
||||
// following checks:
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
const ContentInfo* current_local_msection =
|
||||
FindTransceiverMSection(transceiver.get(), description);
|
||||
|
||||
const ContentInfo* current_remote_msection = FindTransceiverMSection(
|
||||
transceiver.get(), current_remote_description());
|
||||
|
||||
// 4.3 If transceiver is stopped and is associated with an m= section,
|
||||
// but the associated m= section is not yet rejected in
|
||||
// connection.[[CurrentLocalDescription]] or
|
||||
// connection.[[CurrentRemoteDescription]], return true.
|
||||
if (transceiver->stopped()) {
|
||||
if (current_local_msection && !current_local_msection->rejected &&
|
||||
((current_remote_msection && !current_remote_msection->rejected) ||
|
||||
!current_remote_msection)) {
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4.1 If transceiver isn't stopped and isn't yet associated with an m=
|
||||
// section in description, return true.
|
||||
if (!current_local_msection)
|
||||
return true;
|
||||
|
||||
const MediaContentDescription* current_local_media_description =
|
||||
current_local_msection->media_description();
|
||||
// 4.2 If transceiver isn't stopped and is associated with an m= section
|
||||
// in description then perform the following checks:
|
||||
|
||||
// 4.2.1 If transceiver.[[Direction]] is "sendrecv" or "sendonly", and the
|
||||
// associated m= section in description either doesn't contain a single
|
||||
// "a=msid" line, or the number of MSIDs from the "a=msid" lines in this
|
||||
// m= section, or the MSID values themselves, differ from what is in
|
||||
// transceiver.sender.[[AssociatedMediaStreamIds]], return true.
|
||||
if (RtpTransceiverDirectionHasSend(transceiver->direction())) {
|
||||
if (current_local_media_description->streams().size() == 0)
|
||||
return true;
|
||||
|
||||
std::vector<std::string> msection_msids;
|
||||
for (const auto& stream : current_local_media_description->streams()) {
|
||||
for (const std::string& msid : stream.stream_ids())
|
||||
msection_msids.push_back(msid);
|
||||
}
|
||||
|
||||
std::vector<std::string> transceiver_msids =
|
||||
transceiver->sender()->stream_ids();
|
||||
if (msection_msids.size() != transceiver_msids.size())
|
||||
return true;
|
||||
|
||||
absl::c_sort(transceiver_msids);
|
||||
absl::c_sort(msection_msids);
|
||||
if (transceiver_msids != msection_msids)
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4.2.2 If description is of type "offer", and the direction of the
|
||||
// associated m= section in neither connection.[[CurrentLocalDescription]]
|
||||
// nor connection.[[CurrentRemoteDescription]] matches
|
||||
// transceiver.[[Direction]], return true.
|
||||
if (description->GetType() == SdpType::kOffer) {
|
||||
if (!current_remote_description())
|
||||
return true;
|
||||
|
||||
if (!current_remote_msection)
|
||||
return true;
|
||||
|
||||
RtpTransceiverDirection current_local_direction =
|
||||
current_local_media_description->direction();
|
||||
RtpTransceiverDirection current_remote_direction =
|
||||
current_remote_msection->media_description()->direction();
|
||||
if (transceiver->direction() != current_local_direction &&
|
||||
transceiver->direction() !=
|
||||
RtpTransceiverDirectionReversed(current_remote_direction)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 4.2.3 If description is of type "answer", and the direction of the
|
||||
// associated m= section in the description does not match
|
||||
// transceiver.[[Direction]] intersected with the offered direction (as
|
||||
// described in [JSEP] (section 5.3.1.)), return true.
|
||||
if (description->GetType() == SdpType::kAnswer) {
|
||||
if (!remote_description())
|
||||
return true;
|
||||
|
||||
const ContentInfo* offered_remote_msection =
|
||||
FindTransceiverMSection(transceiver.get(), remote_description());
|
||||
|
||||
RtpTransceiverDirection offered_direction =
|
||||
offered_remote_msection
|
||||
? offered_remote_msection->media_description()->direction()
|
||||
: RtpTransceiverDirection::kInactive;
|
||||
|
||||
if (current_local_media_description->direction() !=
|
||||
(RtpTransceiverDirectionIntersection(
|
||||
transceiver->direction(),
|
||||
RtpTransceiverDirectionReversed(offered_direction)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all the preceding checks were performed and true was not returned,
|
||||
// nothing remains to be negotiated; return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -1086,6 +1086,9 @@ class PeerConnection : public PeerConnectionInternal,
|
|||
return media_transport;
|
||||
}
|
||||
|
||||
void UpdateNegotiationNeeded();
|
||||
bool CheckIfNegotiationIsNeeded();
|
||||
|
||||
sigslot::signal1<DataChannel*> SignalDataChannelCreated_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
|
||||
|
@ -1329,6 +1332,7 @@ class PeerConnection : public PeerConnectionInternal,
|
|||
// channel manager and the session description factory.
|
||||
rtc::UniqueRandomIdGenerator ssrc_generator_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
bool is_negotiation_needed_ RTC_GUARDED_BY(signaling_thread()) = false;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -814,8 +814,6 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test {
|
|||
auto sender_or_error =
|
||||
pc_->AddTrack(CreateVideoTrack(track_label), stream_ids);
|
||||
ASSERT_EQ(RTCErrorType::NONE, sender_or_error.error().type());
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
}
|
||||
|
||||
void AddVideoStream(const std::string& label) {
|
||||
|
@ -823,8 +821,6 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test {
|
|||
pc_factory_->CreateLocalMediaStream(label));
|
||||
stream->AddTrack(CreateVideoTrack(label + "v0"));
|
||||
ASSERT_TRUE(pc_->AddStream(stream));
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
|
||||
|
@ -837,8 +833,6 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test {
|
|||
auto sender_or_error =
|
||||
pc_->AddTrack(CreateAudioTrack(track_label), stream_ids);
|
||||
ASSERT_EQ(RTCErrorType::NONE, sender_or_error.error().type());
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
}
|
||||
|
||||
void AddAudioStream(const std::string& label) {
|
||||
|
@ -846,8 +840,6 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test {
|
|||
pc_factory_->CreateLocalMediaStream(label));
|
||||
stream->AddTrack(CreateAudioTrack(label + "a0"));
|
||||
ASSERT_TRUE(pc_->AddStream(stream));
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
}
|
||||
|
||||
void AddAudioVideoStream(const std::string& stream_id,
|
||||
|
@ -859,8 +851,6 @@ class PeerConnectionInterfaceBaseTest : public ::testing::Test {
|
|||
stream->AddTrack(CreateAudioTrack(audio_track_label));
|
||||
stream->AddTrack(CreateVideoTrack(video_track_label));
|
||||
ASSERT_TRUE(pc_->AddStream(stream));
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpReceiverInterface> GetFirstReceiverOfType(
|
||||
|
@ -2204,9 +2194,12 @@ TEST_P(PeerConnectionInterfaceTest, RenegotiationNeededForNewRtpDataChannel) {
|
|||
EXPECT_TRUE(observer_.renegotiation_needed_);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
|
||||
CreateOfferReceiveAnswer();
|
||||
|
||||
rtc::scoped_refptr<DataChannelInterface> dc2 =
|
||||
pc_->CreateDataChannel("test2", NULL);
|
||||
EXPECT_TRUE(observer_.renegotiation_needed_);
|
||||
EXPECT_EQ(observer_.renegotiation_needed_,
|
||||
GetParam() == SdpSemantics::kPlanB);
|
||||
}
|
||||
|
||||
// This test that a data channel closes when a PeerConnection is deleted/closed.
|
||||
|
@ -3894,14 +3887,17 @@ TEST_F(PeerConnectionInterfaceTestPlanB,
|
|||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
|
||||
CreateOfferReceiveAnswer();
|
||||
stream->AddTrack(video_track);
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
|
||||
CreateOfferReceiveAnswer();
|
||||
stream->RemoveTrack(audio_track);
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
|
||||
CreateOfferReceiveAnswer();
|
||||
stream->RemoveTrack(video_track);
|
||||
EXPECT_TRUE_WAIT(observer_.renegotiation_needed_, kTimeout);
|
||||
observer_.renegotiation_needed_ = false;
|
||||
|
|
|
@ -1135,11 +1135,14 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
|||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
AddTrackChangesDirectionFromInactiveToSendOnly) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kInactive;
|
||||
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
ASSERT_TRUE(caller->AddAudioTrack("a"));
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
@ -1152,11 +1155,14 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
|||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
AddTrackChangesDirectionFromRecvOnlyToSendRecv) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kRecvOnly;
|
||||
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
ASSERT_TRUE(caller->AddAudioTrack("a"));
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
@ -1219,18 +1225,21 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan, RemoveTrackClearsSenderTrack) {
|
|||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
RemoveTrackChangesDirectionFromSendRecvToRecvOnly) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kSendRecv;
|
||||
auto transceiver =
|
||||
caller->AddTransceiver(caller->CreateAudioTrack("a"), init);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
|
||||
ASSERT_TRUE(caller->pc()->RemoveTrack(transceiver->sender()));
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceiver->direction());
|
||||
EXPECT_TRUE(caller->observer()->renegotiation_needed_);
|
||||
}
|
||||
|
||||
// Test that calling RemoveTrack on a sender where the transceiver is configured
|
||||
|
@ -1238,13 +1247,17 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
|||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
RemoveTrackChangesDirectionFromSendOnlyToInactive) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kSendOnly;
|
||||
auto transceiver =
|
||||
caller->AddTransceiver(caller->CreateAudioTrack("a"), init);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
|
||||
ASSERT_TRUE(caller->pc()->RemoveTrack(transceiver->sender()));
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
|
@ -1394,10 +1407,15 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
|||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
RenegotiationNeededAfterTransceiverSetDirection) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
EXPECT_FALSE(caller->observer()->negotiation_needed());
|
||||
|
||||
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
|
||||
transceiver->SetDirection(RtpTransceiverDirection::kInactive);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
}
|
||||
|
@ -1777,6 +1795,42 @@ TEST_P(PeerConnectionRtpTest, CreateTwoSendersWithSameTrack) {
|
|||
}
|
||||
}
|
||||
|
||||
// This test exercises the code path that fires a NegotiationNeeded
|
||||
// notification when the stream IDs of the local description differ from
|
||||
// the ones in the transceiver. Since SetStreams() is not yet available
|
||||
// on RtpSenderInterface, adding a track is used to trigger the check for
|
||||
// the NegotiationNeeded notification.
|
||||
// TODO(https://crbug.com/webrtc/10129): Replace this test with a test that
|
||||
// checks that calling SetStreams() on a sender fires the notification once
|
||||
// the method becomes available in RtpSenderInterface.
|
||||
TEST_F(PeerConnectionRtpTestUnifiedPlan,
|
||||
ChangeAssociatedStreamsTriggersRenegotiation) {
|
||||
auto caller = CreatePeerConnection();
|
||||
auto callee = CreatePeerConnection();
|
||||
|
||||
RtpTransceiverInit init;
|
||||
init.direction = RtpTransceiverDirection::kSendRecv;
|
||||
auto transceiver =
|
||||
caller->AddTransceiver(caller->CreateAudioTrack("a"), init);
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
|
||||
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
|
||||
caller->observer()->clear_negotiation_needed();
|
||||
|
||||
SessionDescriptionInterface* cld = const_cast<SessionDescriptionInterface*>(
|
||||
caller->pc()->current_local_description());
|
||||
ASSERT_EQ(cld->description()->contents().size(), 1u);
|
||||
|
||||
cricket::SessionDescription* description = cld->description();
|
||||
cricket::ContentInfo& content_info = description->contents()[0];
|
||||
ASSERT_EQ(content_info.media_description()->mutable_streams().size(), 1u);
|
||||
content_info.media_description()->mutable_streams()[0].set_stream_ids(
|
||||
{"stream3", "stream4", "stream5"});
|
||||
|
||||
ASSERT_TRUE(caller->AddTrack(caller->CreateAudioTrack("a2")));
|
||||
EXPECT_TRUE(caller->observer()->negotiation_needed());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(PeerConnectionRtpTest,
|
||||
PeerConnectionRtpTest,
|
||||
Values(SdpSemantics::kPlanB,
|
||||
|
|
|
@ -81,4 +81,14 @@ const char* RtpTransceiverDirectionToString(RtpTransceiverDirection direction) {
|
|||
return "";
|
||||
}
|
||||
|
||||
RtpTransceiverDirection RtpTransceiverDirectionIntersection(
|
||||
RtpTransceiverDirection lhs,
|
||||
RtpTransceiverDirection rhs) {
|
||||
return RtpTransceiverDirectionFromSendRecv(
|
||||
RtpTransceiverDirectionHasSend(lhs) &&
|
||||
RtpTransceiverDirectionHasSend(rhs),
|
||||
RtpTransceiverDirectionHasRecv(lhs) &&
|
||||
RtpTransceiverDirectionHasRecv(rhs));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -44,6 +44,11 @@ RtpTransceiverDirection RtpTransceiverDirectionWithRecvSet(
|
|||
// Returns an unspecified string representation of the given direction.
|
||||
const char* RtpTransceiverDirectionToString(RtpTransceiverDirection direction);
|
||||
|
||||
// Returns the intersection of the directions of two transceivers.
|
||||
RtpTransceiverDirection RtpTransceiverDirectionIntersection(
|
||||
RtpTransceiverDirection lhs,
|
||||
RtpTransceiverDirection rhs);
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
|
||||
std::ostream& os, // no-presubmit-check TODO(webrtc:8982)
|
||||
|
|
|
@ -1132,8 +1132,10 @@ public class PeerConnectionTest {
|
|||
System.gc();
|
||||
}
|
||||
|
||||
// TODO(https://bugs.webrtc.org/10526): Fix and re-enable this test.
|
||||
@Test
|
||||
@MediumTest
|
||||
@DisabledTest
|
||||
public void testDataChannelOnlySession() throws Exception {
|
||||
// Allow loopback interfaces too since our Android devices often don't
|
||||
// have those.
|
||||
|
@ -1291,8 +1293,10 @@ public class PeerConnectionTest {
|
|||
System.gc();
|
||||
}
|
||||
|
||||
// TODO(https://bugs.webrtc.org/10526): Fix and re-enable this test.
|
||||
@Test
|
||||
@MediumTest
|
||||
@DisabledTest
|
||||
public void testTrackRemovalAndAddition() throws Exception {
|
||||
// Allow loopback interfaces too since our Android devices often don't
|
||||
// have those.
|
||||
|
|
Loading…
Reference in a new issue