Modify Bundle logic to not add & destroy extra transport at add-track
If a bundle is established, then per JSEP, the offerer is required to include the new track in the bundle, and per BUNDLE, the answerer has to either accept the track as part of the bundle or reject the track; it cannot move it out of the group. So we will never need the transport. Bug: webrtc:12837 Change-Id: I41cae74605fecf454900a958776b95607ccf3745 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/221601 Reviewed-by: Henrik Boström <hbos@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34290}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
e4eb8af08f
commit
7a2db8acbe
@ -574,6 +574,18 @@ RTCError JsepTransportController::ApplyDescription_n(
|
|||||||
established_bundle_groups_by_mid, description);
|
established_bundle_groups_by_mid, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Because the creation of transports depends on whether
|
||||||
|
// certain mids are present, we have to process rejection
|
||||||
|
// before we try to create transports.
|
||||||
|
for (size_t i = 0; i < description->contents().size(); ++i) {
|
||||||
|
const cricket::ContentInfo& content_info = description->contents()[i];
|
||||||
|
if (content_info.rejected) {
|
||||||
|
// This may cause groups to be removed from |bundles_.bundle_groups()| and
|
||||||
|
// |established_bundle_groups_by_mid|.
|
||||||
|
HandleRejectedContent(content_info, established_bundle_groups_by_mid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const cricket::ContentInfo& content_info : description->contents()) {
|
for (const cricket::ContentInfo& content_info : description->contents()) {
|
||||||
// Don't create transports for rejected m-lines and bundled m-lines.
|
// Don't create transports for rejected m-lines and bundled m-lines.
|
||||||
if (content_info.rejected ||
|
if (content_info.rejected ||
|
||||||
@ -593,10 +605,8 @@ RTCError JsepTransportController::ApplyDescription_n(
|
|||||||
const cricket::ContentInfo& content_info = description->contents()[i];
|
const cricket::ContentInfo& content_info = description->contents()[i];
|
||||||
const cricket::TransportInfo& transport_info =
|
const cricket::TransportInfo& transport_info =
|
||||||
description->transport_infos()[i];
|
description->transport_infos()[i];
|
||||||
|
|
||||||
if (content_info.rejected) {
|
if (content_info.rejected) {
|
||||||
// This may cause groups to be removed from |bundles_.bundle_groups()| and
|
|
||||||
// |established_bundle_groups_by_mid|.
|
|
||||||
HandleRejectedContent(content_info, established_bundle_groups_by_mid);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,7 +1021,21 @@ RTCError JsepTransportController::MaybeCreateJsepTransport(
|
|||||||
if (transport) {
|
if (transport) {
|
||||||
return RTCError::OK();
|
return RTCError::OK();
|
||||||
}
|
}
|
||||||
|
// If we have agreed to a bundle, the new mid will be added to the bundle
|
||||||
|
// according to JSEP, and the responder can't move it out of the group
|
||||||
|
// according to BUNDLE. So don't create a transport.
|
||||||
|
// The MID will be added to the bundle elsewhere in the code.
|
||||||
|
if (bundles_.bundle_groups().size() > 0) {
|
||||||
|
const auto& default_bundle_group = bundles_.bundle_groups()[0];
|
||||||
|
if (default_bundle_group->content_names().size() > 0) {
|
||||||
|
auto bundle_transport =
|
||||||
|
GetJsepTransportByName(default_bundle_group->content_names()[0]);
|
||||||
|
if (bundle_transport) {
|
||||||
|
transports_.SetTransportForMid(content_info.name, bundle_transport);
|
||||||
|
return RTCError::OK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
const cricket::MediaContentDescription* content_desc =
|
const cricket::MediaContentDescription* content_desc =
|
||||||
content_info.media_description();
|
content_info.media_description();
|
||||||
if (certificate_ && !content_desc->cryptos().empty()) {
|
if (certificate_ && !content_desc->cryptos().empty()) {
|
||||||
|
|||||||
@ -2051,7 +2051,6 @@ TEST_F(JsepTransportControllerTest, ChangeTaggedMediaSectionMaxBundle) {
|
|||||||
EXPECT_TRUE(transport_controller_
|
EXPECT_TRUE(transport_controller_
|
||||||
->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
|
->SetLocalDescription(SdpType::kOffer, local_reoffer.get())
|
||||||
.ok());
|
.ok());
|
||||||
|
|
||||||
std::unique_ptr<cricket::SessionDescription> remote_reanswer(
|
std::unique_ptr<cricket::SessionDescription> remote_reanswer(
|
||||||
local_reoffer->Clone());
|
local_reoffer->Clone());
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
|
|||||||
@ -3639,6 +3639,20 @@ TEST_P(PeerConnectionIntegrationInteropTest,
|
|||||||
ASSERT_TRUE(ExpectNewFrames(media_expectations));
|
ASSERT_TRUE(ExpectNewFrames(media_expectations));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(PeerConnectionIntegrationTest, NewTracksDoNotCauseNewCandidates) {
|
||||||
|
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||||
|
ConnectFakeSignaling();
|
||||||
|
caller()->AddAudioVideoTracks();
|
||||||
|
caller()->CreateAndSetAndSignalOffer();
|
||||||
|
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||||
|
ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
|
||||||
|
caller()->ExpectCandidates(0);
|
||||||
|
callee()->ExpectCandidates(0);
|
||||||
|
caller()->AddAudioTrack();
|
||||||
|
caller()->CreateAndSetAndSignalOffer();
|
||||||
|
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
PeerConnectionIntegrationTest,
|
PeerConnectionIntegrationTest,
|
||||||
PeerConnectionIntegrationInteropTest,
|
PeerConnectionIntegrationInteropTest,
|
||||||
|
|||||||
@ -91,7 +91,8 @@ bool RtcpMuxFilter::SetAnswer(bool answer_enable, ContentSource src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ExpectAnswer(src)) {
|
if (!ExpectAnswer(src)) {
|
||||||
RTC_LOG(LS_ERROR) << "Invalid state for RTCP mux answer";
|
RTC_LOG(LS_ERROR) << "Invalid state for RTCP mux answer, state is "
|
||||||
|
<< state_ << ", source is " << src;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,18 @@ bool ContentGroup::RemoveContentName(const std::string& content_name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ContentGroup::ToString() const {
|
||||||
|
rtc::StringBuilder acc;
|
||||||
|
acc << semantics_ << "(";
|
||||||
|
if (!content_names_.empty()) {
|
||||||
|
for (const auto& name : content_names_) {
|
||||||
|
acc << name << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc << ")";
|
||||||
|
return acc.Release();
|
||||||
|
}
|
||||||
|
|
||||||
SessionDescription::SessionDescription() = default;
|
SessionDescription::SessionDescription() = default;
|
||||||
SessionDescription::SessionDescription(const SessionDescription&) = default;
|
SessionDescription::SessionDescription(const SessionDescription&) = default;
|
||||||
|
|
||||||
|
|||||||
@ -488,6 +488,8 @@ class ContentGroup {
|
|||||||
bool HasContentName(const std::string& content_name) const;
|
bool HasContentName(const std::string& content_name) const;
|
||||||
void AddContentName(const std::string& content_name);
|
void AddContentName(const std::string& content_name);
|
||||||
bool RemoveContentName(const std::string& content_name);
|
bool RemoveContentName(const std::string& content_name);
|
||||||
|
// for debugging
|
||||||
|
std::string ToString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string semantics_;
|
std::string semantics_;
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <limits>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -704,6 +705,11 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
|
|||||||
audio_concealed_stat_ = *track_stats->concealed_samples;
|
audio_concealed_stat_ = *track_stats->concealed_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets number of candidates expected
|
||||||
|
void ExpectCandidates(int candidate_count) {
|
||||||
|
candidates_expected_ = candidate_count;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit PeerConnectionIntegrationWrapper(const std::string& debug_name)
|
explicit PeerConnectionIntegrationWrapper(const std::string& debug_name)
|
||||||
: debug_name_(debug_name) {}
|
: debug_name_(debug_name) {}
|
||||||
@ -1089,6 +1095,9 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we expected to have a candidate.
|
||||||
|
EXPECT_GT(candidates_expected_, 1);
|
||||||
|
candidates_expected_--;
|
||||||
std::string ice_sdp;
|
std::string ice_sdp;
|
||||||
EXPECT_TRUE(candidate->ToString(&ice_sdp));
|
EXPECT_TRUE(candidate->ToString(&ice_sdp));
|
||||||
if (signaling_message_receiver_ == nullptr || !signal_ice_candidates_) {
|
if (signaling_message_receiver_ == nullptr || !signal_ice_candidates_) {
|
||||||
@ -1172,6 +1181,9 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
|
|||||||
peer_connection_signaling_state_history_;
|
peer_connection_signaling_state_history_;
|
||||||
webrtc::FakeRtcEventLogFactory* event_log_factory_;
|
webrtc::FakeRtcEventLogFactory* event_log_factory_;
|
||||||
|
|
||||||
|
// Number of ICE candidates expected. The default is no limit.
|
||||||
|
int candidates_expected_ = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
// Variables for tracking delay stats on an audio track
|
// Variables for tracking delay stats on an audio track
|
||||||
int audio_packets_stat_ = 0;
|
int audio_packets_stat_ = 0;
|
||||||
double audio_delay_stat_ = 0.0;
|
double audio_delay_stat_ = 0.0;
|
||||||
|
|||||||
Reference in New Issue
Block a user