Add optional init_send_encodings to AddTrack

This patch adds variant of PeerConnectionInterface::AddTrack
that takes an initial_send_encodings.

This allows for setting/modifying encoding parameters before sdp
negotiation is performed/complete (e.g requested_resolution).

This is already available if using RtpTransciverInit and AddTransceiver,
but was not added to AddTrack because of concerns that it complicated matching with existing transceivers. This CL sidesteps that by never matching to a preexisting transceiver if initial_send_encodings are specified.

Note:
1) The patch adds a new method rather than an extra (e.g optional)
argument to existing AddTrack. This is to avoid problems with downstream mocks.

2) chromium "problems" was fixed in https://chromium-review.googlesource.com/c/chromium/src/+/3952684 and https://chromium-review.googlesource.com/c/chromium/src/+/3956060

Bug: webrtc:14451
Change-Id: I19b5a03872730280fbf868ca5d3a2f46443359f3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/278783
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38437}
This commit is contained in:
Jonas Oreland 2022-10-19 09:24:42 +02:00 committed by WebRTC LUCI CQ
parent 5a92577a94
commit 4b2a106af2
13 changed files with 174 additions and 14 deletions

View File

@ -804,6 +804,16 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) = 0;
// Add a new MediaStreamTrack as above, but with an additional parameter,
// `init_send_encodings` : initial RtpEncodingParameters for RtpSender,
// similar to init_send_encodings in RtpTransceiverInit.
// Note that a new transceiver will always be created.
//
virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings) = 0;
// Removes the connection between a MediaStreamTrack and the PeerConnection.
// Stops sending on the RtpSender and marks the
// corresponding RtpTransceiver direction as no longer sending.

View File

@ -47,6 +47,12 @@ class MockPeerConnectionInterface : public webrtc::PeerConnectionInterface {
(rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&),
(override));
MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
AddTrack,
(rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&,
const std::vector<RtpEncodingParameters>&),
(override));
MOCK_METHOD(RTCError,
RemoveTrackOrError,
(rtc::scoped_refptr<RtpSenderInterface>),

View File

@ -836,6 +836,20 @@ void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) {
return AddTrack(std::move(track), stream_ids, nullptr);
}
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings) {
return AddTrack(std::move(track), stream_ids, &init_send_encodings);
}
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings) {
RTC_DCHECK_RUN_ON(signaling_thread());
TRACE_EVENT0("webrtc", "PeerConnection::AddTrack");
if (!ConfiguredForMedia()) {
@ -859,7 +873,8 @@ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::AddTrack(
RTCErrorType::INVALID_PARAMETER,
"Sender already exists for track " + track->id() + ".");
}
auto sender_or_error = rtp_manager()->AddTrack(track, stream_ids);
auto sender_or_error =
rtp_manager()->AddTrack(track, stream_ids, init_send_encodings);
if (sender_or_error.ok()) {
sdp_handler_->UpdateNegotiationNeeded();
legacy_stats_->AddTrack(track.get());

View File

@ -129,6 +129,14 @@ class PeerConnection : public PeerConnectionInternal,
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) override;
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings) override;
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings);
RTCError RemoveTrackOrError(
rtc::scoped_refptr<RtpSenderInterface> sender) override;

View File

@ -441,7 +441,9 @@ class RtcEventLogOutputNull final : public RtcEventLogOutput {
};
using ::cricket::StreamParams;
using ::testing::Eq;
using ::testing::Exactly;
using ::testing::SizeIs;
using ::testing::Values;
using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
@ -1580,6 +1582,57 @@ TEST_F(PeerConnectionInterfaceTestPlanB, AddTrackRemoveTrack) {
EXPECT_FALSE(pc_->RemoveTrackOrError(video_sender).ok());
}
// Test for AddTrack with init_send_encoding.
TEST_F(PeerConnectionInterfaceTestPlanB, AddTrackWithSendEncodings) {
CreatePeerConnectionWithoutDtls();
rtc::scoped_refptr<AudioTrackInterface> audio_track(
CreateAudioTrack("audio_track"));
rtc::scoped_refptr<VideoTrackInterface> video_track(
CreateVideoTrack("video_track"));
RtpEncodingParameters audio_encodings;
audio_encodings.active = false;
auto audio_sender =
pc_->AddTrack(audio_track, {kStreamId1}, {audio_encodings}).MoveValue();
RtpEncodingParameters video_encodings;
video_encodings.active = true;
auto video_sender =
pc_->AddTrack(video_track, {kStreamId1}, {video_encodings}).MoveValue();
EXPECT_EQ(1UL, audio_sender->stream_ids().size());
EXPECT_EQ(kStreamId1, audio_sender->stream_ids()[0]);
EXPECT_EQ("audio_track", audio_sender->id());
EXPECT_EQ(audio_track, audio_sender->track());
EXPECT_EQ(1UL, video_sender->stream_ids().size());
EXPECT_EQ(kStreamId1, video_sender->stream_ids()[0]);
EXPECT_EQ("video_track", video_sender->id());
EXPECT_EQ(video_track, video_sender->track());
// Now create an offer and check for the senders.
std::unique_ptr<SessionDescriptionInterface> offer;
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
const cricket::ContentInfo* audio_content =
cricket::GetFirstAudioContent(offer->description());
EXPECT_TRUE(ContainsTrack(audio_content->media_description()->streams(),
kStreamId1, "audio_track"));
const cricket::ContentInfo* video_content =
cricket::GetFirstVideoContent(offer->description());
EXPECT_TRUE(ContainsTrack(video_content->media_description()->streams(),
kStreamId1, "video_track"));
EXPECT_TRUE(DoSetLocalDescription(std::move(offer)));
// Check the encodings.
ASSERT_THAT(audio_sender->GetParameters().encodings, SizeIs(1));
EXPECT_THAT(audio_sender->GetParameters().encodings[0].active, Eq(false));
ASSERT_THAT(video_sender->GetParameters().encodings, SizeIs(1));
EXPECT_THAT(video_sender->GetParameters().encodings[0].active, Eq(true));
// Now try removing the tracks.
EXPECT_TRUE(pc_->RemoveTrackOrError(audio_sender).ok());
EXPECT_TRUE(pc_->RemoveTrackOrError(video_sender).ok());
}
// Test creating senders without a stream specified,
// expecting a random stream ID to be generated.
TEST_P(PeerConnectionInterfaceTest, AddTrackWithoutStream) {

View File

@ -35,6 +35,11 @@ PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
AddTrack,
rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&)
PROXY_METHOD3(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
AddTrack,
rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&,
const std::vector<RtpEncodingParameters>&)
PROXY_METHOD1(RTCError,
RemoveTrackOrError,
rtc::scoped_refptr<RtpSenderInterface>)

View File

@ -1145,6 +1145,23 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan, AddTrackReusesTransceiver) {
EXPECT_EQ(audio_track, sender->track());
}
TEST_F(PeerConnectionRtpTestUnifiedPlan,
AddTrackWithSendEncodingDoesNotReuseTransceiver) {
auto caller = CreatePeerConnection();
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
auto audio_track = caller->CreateAudioTrack("a");
RtpEncodingParameters encoding;
auto sender = caller->AddTrack(audio_track, {}, {encoding});
ASSERT_TRUE(sender);
auto transceivers = caller->pc()->GetTransceivers();
ASSERT_EQ(2u, transceivers.size());
EXPECT_EQ(transceiver, transceivers[0]);
EXPECT_NE(sender, transceiver->sender());
EXPECT_EQ(audio_track, sender->track());
}
// Test that adding two tracks to a new PeerConnection creates two
// RtpTransceivers in the same order.
TEST_F(PeerConnectionRtpTestUnifiedPlan, TwoAddTrackCreatesTwoTransceivers) {

View File

@ -289,6 +289,16 @@ rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddTrack(
return result.MoveValue();
}
rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings) {
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> result =
pc()->AddTrack(track, stream_ids, init_send_encodings);
EXPECT_EQ(RTCErrorType::NONE, result.error().type());
return result.MoveValue();
}
rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddAudioTrack(
const std::string& track_label,
const std::vector<std::string>& stream_ids) {

View File

@ -149,6 +149,11 @@ class PeerConnectionWrapper {
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids = {});
rtc::scoped_refptr<RtpSenderInterface> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings);
// Calls the underlying PeerConnection's AddTrack method with an audio media
// stream track not bound to any source.
rtc::scoped_refptr<RtpSenderInterface> AddAudioTrack(

View File

@ -99,17 +99,20 @@ cricket::VideoMediaChannel* RtpTransmissionManager::video_media_channel()
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
RtpTransmissionManager::AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) {
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings) {
RTC_DCHECK_RUN_ON(signaling_thread());
return (IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
: AddTrackPlanB(track, stream_ids));
return (IsUnifiedPlan()
? AddTrackUnifiedPlan(track, stream_ids, init_send_encodings)
: AddTrackPlanB(track, stream_ids, init_send_encodings));
}
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
RtpTransmissionManager::AddTrackPlanB(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) {
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (stream_ids.size() > 1u) {
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
@ -125,7 +128,9 @@ RtpTransmissionManager::AddTrackPlanB(
? cricket::MEDIA_TYPE_AUDIO
: cricket::MEDIA_TYPE_VIDEO);
auto new_sender =
CreateSender(media_type, track->id(), track, adjusted_stream_ids, {});
CreateSender(media_type, track->id(), track, adjusted_stream_ids,
init_send_encodings ? *init_send_encodings
: std::vector<RtpEncodingParameters>());
if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
new_sender->internal()->SetMediaChannel(voice_media_channel());
GetAudioTransceiver()->internal()->AddSender(new_sender);
@ -152,8 +157,10 @@ RtpTransmissionManager::AddTrackPlanB(
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
RtpTransmissionManager::AddTrackUnifiedPlan(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) {
auto transceiver = FindFirstTransceiverForAddedTrack(track);
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings) {
auto transceiver =
FindFirstTransceiverForAddedTrack(track, init_send_encodings);
if (transceiver) {
RTC_LOG(LS_INFO) << "Reusing an existing "
<< cricket::MediaTypeToString(transceiver->media_type())
@ -187,7 +194,10 @@ RtpTransmissionManager::AddTrackUnifiedPlan(
if (FindSenderById(sender_id)) {
sender_id = rtc::CreateRandomUuid();
}
auto sender = CreateSender(media_type, sender_id, track, stream_ids, {});
auto sender = CreateSender(media_type, sender_id, track, stream_ids,
init_send_encodings
? *init_send_encodings
: std::vector<RtpEncodingParameters>());
auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
transceiver = CreateAndAddTransceiver(sender, receiver);
transceiver->internal()->set_created_by_addtrack(true);
@ -280,9 +290,13 @@ RtpTransmissionManager::CreateAndAddTransceiver(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
RtpTransmissionManager::FindFirstTransceiverForAddedTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track) {
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<RtpEncodingParameters>* init_send_encodings) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(track);
if (init_send_encodings != nullptr) {
return nullptr;
}
for (auto transceiver : transceivers()->List()) {
if (!transceiver->sender()->track() &&
cricket::MediaTypeToString(transceiver->media_type()) ==

View File

@ -95,7 +95,8 @@ class RtpTransmissionManager : public RtpSenderBase::SetStreamsObserver {
// Add a new track, creating transceiver if required.
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids);
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings);
// Create a new RTP sender. Does not associate with a transceiver.
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
@ -121,7 +122,8 @@ class RtpTransmissionManager : public RtpSenderBase::SetStreamsObserver {
// transceiver is available.
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
FindFirstTransceiverForAddedTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track);
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<RtpEncodingParameters>* init_send_encodings);
// Returns the list of senders currently associated with some
// registered transceiver
@ -220,11 +222,13 @@ class RtpTransmissionManager : public RtpSenderBase::SetStreamsObserver {
// AddTrack implementation when Unified Plan is specified.
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrackUnifiedPlan(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids);
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings);
// AddTrack implementation when Plan B is specified.
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrackPlanB(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids);
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>* init_send_encodings);
// Create an RtpReceiver that sources an audio track.
void CreateAudioReceiver(MediaStreamInterface* stream,

View File

@ -50,6 +50,13 @@ class FakePeerConnectionBase : public PeerConnectionInternal {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
}
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids,
const std::vector<RtpEncodingParameters>& init_send_encodings) override {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
}
RTCError RemoveTrackOrError(
rtc::scoped_refptr<RtpSenderInterface> sender) override {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION);

View File

@ -42,6 +42,12 @@ class MockPeerConnectionInternal : public PeerConnectionInternal {
(rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&),
(override));
MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
AddTrack,
(rtc::scoped_refptr<MediaStreamTrackInterface>,
const std::vector<std::string>&,
const std::vector<RtpEncodingParameters>&),
(override));
MOCK_METHOD(RTCError,
RemoveTrackOrError,
(rtc::scoped_refptr<RtpSenderInterface>),