Improve spec compliance of SetStreamIDs in RtpSenderInterface

This CL makes RtpSender::SetStreamIDs fire fire negotiationneeded
event if needed and exposes the method on RtpSenderInterface.

This is a spec-compliance change.

Bug: webrtc:10129
Change-Id: I2b98b92665c847102838b094516a79b24de0e47e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135121
Commit-Queue: Guido Urdaneta <guidou@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27974}
This commit is contained in:
Guido Urdaneta 2019-05-17 14:23:05 +02:00 committed by Commit Bot
parent 519d74a5fc
commit df5731e44d
8 changed files with 157 additions and 83 deletions

View file

@ -61,6 +61,11 @@ class RtpSenderInterface : public rtc::RefCountInterface {
// tracks. // tracks.
virtual std::vector<std::string> stream_ids() const = 0; virtual std::vector<std::string> stream_ids() const = 0;
// Sets the IDs of the media streams associated with this sender's track.
// These are signalled in the SDP so that the remote side can associate
// tracks.
virtual void SetStreamIDs(const std::vector<std::string>& stream_ids) {}
// Returns the list of encoding parameters that will be applied when the SDP // Returns the list of encoding parameters that will be applied when the SDP
// local description is set. These initial encoding parameters can be set by // local description is set. These initial encoding parameters can be set by
// PeerConnection::AddTransceiver, and later updated with Get/SetParameters. // PeerConnection::AddTransceiver, and later updated with Get/SetParameters.
@ -112,6 +117,7 @@ PROXY_METHOD1(void,
rtc::scoped_refptr<FrameEncryptorInterface>) rtc::scoped_refptr<FrameEncryptorInterface>)
PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameEncryptorInterface>, PROXY_CONSTMETHOD0(rtc::scoped_refptr<FrameEncryptorInterface>,
GetFrameEncryptor) GetFrameEncryptor)
PROXY_METHOD1(void, SetStreamIDs, const std::vector<std::string>&)
END_PROXY_MAP() END_PROXY_MAP()
} // namespace webrtc } // namespace webrtc

View file

@ -1373,7 +1373,7 @@ PeerConnection::AddTrackUnifiedPlan(
RtpTransceiverDirection::kSendOnly); RtpTransceiverDirection::kSendOnly);
} }
transceiver->sender()->SetTrack(track); transceiver->sender()->SetTrack(track);
transceiver->internal()->sender_internal()->set_stream_ids(stream_ids); transceiver->internal()->sender_internal()->SetStreamIDs(stream_ids);
} else { } else {
cricket::MediaType media_type = cricket::MediaType media_type =
(track->kind() == MediaStreamTrackInterface::kAudioKind (track->kind() == MediaStreamTrackInterface::kAudioKind
@ -1632,19 +1632,19 @@ PeerConnection::CreateSender(
(track->kind() == MediaStreamTrackInterface::kAudioKind)); (track->kind() == MediaStreamTrackInterface::kAudioKind));
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create( sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
signaling_thread(), signaling_thread(),
AudioRtpSender::Create(worker_thread(), id, stats_.get())); AudioRtpSender::Create(worker_thread(), id, stats_.get(), this));
NoteUsageEvent(UsageEvent::AUDIO_ADDED); NoteUsageEvent(UsageEvent::AUDIO_ADDED);
} else { } else {
RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
RTC_DCHECK(!track || RTC_DCHECK(!track ||
(track->kind() == MediaStreamTrackInterface::kVideoKind)); (track->kind() == MediaStreamTrackInterface::kVideoKind));
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create( sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
signaling_thread(), VideoRtpSender::Create(worker_thread(), id)); signaling_thread(), VideoRtpSender::Create(worker_thread(), id, this));
NoteUsageEvent(UsageEvent::VIDEO_ADDED); NoteUsageEvent(UsageEvent::VIDEO_ADDED);
} }
bool set_track_succeeded = sender->SetTrack(track); bool set_track_succeeded = sender->SetTrack(track);
RTC_DCHECK(set_track_succeeded); RTC_DCHECK(set_track_succeeded);
sender->internal()->set_stream_ids(stream_ids); sender->internal()->SetStreamIDs(stream_ids);
sender->internal()->set_init_send_encodings(send_encodings); sender->internal()->set_init_send_encodings(send_encodings);
return sender; return sender;
} }
@ -1722,14 +1722,14 @@ rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender; rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
if (kind == MediaStreamTrackInterface::kAudioKind) { if (kind == MediaStreamTrackInterface::kAudioKind) {
auto audio_sender = AudioRtpSender::Create( auto audio_sender = AudioRtpSender::Create(
worker_thread(), rtc::CreateRandomUuid(), stats_.get()); worker_thread(), rtc::CreateRandomUuid(), stats_.get(), this);
audio_sender->SetMediaChannel(voice_media_channel()); audio_sender->SetMediaChannel(voice_media_channel());
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create( new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
signaling_thread(), audio_sender); signaling_thread(), audio_sender);
GetAudioTransceiver()->internal()->AddSender(new_sender); GetAudioTransceiver()->internal()->AddSender(new_sender);
} else if (kind == MediaStreamTrackInterface::kVideoKind) { } else if (kind == MediaStreamTrackInterface::kVideoKind) {
auto video_sender = auto video_sender =
VideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid()); VideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(), this);
video_sender->SetMediaChannel(video_media_channel()); video_sender->SetMediaChannel(video_media_channel());
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create( new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
signaling_thread(), video_sender); signaling_thread(), video_sender);
@ -1738,7 +1738,7 @@ rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
RTC_LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind; RTC_LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
return nullptr; return nullptr;
} }
new_sender->internal()->set_stream_ids(stream_ids); new_sender->internal()->SetStreamIDs(stream_ids);
return new_sender; return new_sender;
} }
@ -2361,7 +2361,7 @@ RTCError PeerConnection::ApplyLocalDescription(
} else { } else {
// Get the StreamParams from the channel which could generate SSRCs. // Get the StreamParams from the channel which could generate SSRCs.
const std::vector<StreamParams>& streams = channel->local_streams(); const std::vector<StreamParams>& streams = channel->local_streams();
transceiver->internal()->sender_internal()->set_stream_ids( transceiver->internal()->sender_internal()->SetStreamIDs(
streams[0].stream_ids()); streams[0].stream_ids());
transceiver->internal()->sender_internal()->SetSsrc( transceiver->internal()->sender_internal()->SetSsrc(
streams[0].first_ssrc()); streams[0].first_ssrc());
@ -4010,7 +4010,7 @@ void PeerConnection::AddAudioTrack(AudioTrackInterface* track,
if (sender) { if (sender) {
// We already have a sender for this track, so just change the stream_id // We already have a sender for this track, so just change the stream_id
// so that it's correct in the next call to CreateOffer. // so that it's correct in the next call to CreateOffer.
sender->internal()->set_stream_ids({stream->id()}); sender->internal()->SetStreamIDs({stream->id()});
return; return;
} }
@ -4055,7 +4055,7 @@ void PeerConnection::AddVideoTrack(VideoTrackInterface* track,
if (sender) { if (sender) {
// We already have a sender for this track, so just change the stream_id // We already have a sender for this track, so just change the stream_id
// so that it's correct in the next call to CreateOffer. // so that it's correct in the next call to CreateOffer.
sender->internal()->set_stream_ids({stream->id()}); sender->internal()->SetStreamIDs({stream->id()});
return; return;
} }
@ -4987,7 +4987,7 @@ void PeerConnection::OnLocalSenderAdded(const RtpSenderInfo& sender_info,
return; return;
} }
sender->internal()->set_stream_ids({sender_info.stream_id}); sender->internal()->SetStreamIDs({sender_info.stream_id});
sender->internal()->SetSsrc(sender_info.first_ssrc); sender->internal()->SetSsrc(sender_info.first_ssrc);
} }
@ -7130,6 +7130,12 @@ bool PeerConnection::OnTransportChanged(
return ret; return ret;
} }
void PeerConnection::OnSetStreamIDs() {
RTC_DCHECK_RUN_ON(signaling_thread());
if (IsUnifiedPlan())
UpdateNegotiationNeeded();
}
PeerConnectionObserver* PeerConnection::Observer() const { PeerConnectionObserver* PeerConnection::Observer() const {
// In earlier production code, the pointer was not cleared on close, // In earlier production code, the pointer was not cleared on close,
// which might have led to undefined behavior if the observer was not // which might have led to undefined behavior if the observer was not

View file

@ -25,6 +25,7 @@
#include "pc/peer_connection_factory.h" #include "pc/peer_connection_factory.h"
#include "pc/peer_connection_internal.h" #include "pc/peer_connection_internal.h"
#include "pc/rtc_stats_collector.h" #include "pc/rtc_stats_collector.h"
#include "pc/rtp_sender.h"
#include "pc/rtp_transceiver.h" #include "pc/rtp_transceiver.h"
#include "pc/sctp_transport.h" #include "pc/sctp_transport.h"
#include "pc/stats_collector.h" #include "pc/stats_collector.h"
@ -57,6 +58,7 @@ class PeerConnection : public PeerConnectionInternal,
public DataChannelProviderInterface, public DataChannelProviderInterface,
public DataChannelSink, public DataChannelSink,
public JsepTransportController::Observer, public JsepTransportController::Observer,
public RtpSenderBase::SetStreamIDsObserver,
public rtc::MessageHandler, public rtc::MessageHandler,
public sigslot::has_slots<> { public sigslot::has_slots<> {
public: public:
@ -1055,6 +1057,9 @@ class PeerConnection : public PeerConnectionInternal,
rtc::scoped_refptr<DtlsTransport> dtls_transport, rtc::scoped_refptr<DtlsTransport> dtls_transport,
MediaTransportInterface* media_transport) override; MediaTransportInterface* media_transport) override;
// RtpSenderBase::SetStreamIDsObserver override.
void OnSetStreamIDs() override;
// Returns the observer. Will crash on CHECK if the observer is removed. // Returns the observer. Will crash on CHECK if the observer is removed.
PeerConnectionObserver* Observer() const RTC_RUN_ON(signaling_thread()); PeerConnectionObserver* Observer() const RTC_RUN_ON(signaling_thread());

View file

@ -491,15 +491,8 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan, ChangeMsidWhileReceiving) {
ASSERT_TRUE(callee->CreateAnswerAndSetAsLocal()); ASSERT_TRUE(callee->CreateAnswerAndSetAsLocal());
// Change the stream ID in the offer. // Change the stream ID in the offer.
// TODO(https://crbug.com/webrtc/10129): When RtpSenderInterface::SetStreams caller->pc()->GetSenders()[0]->SetStreamIDs({"stream2"});
// is supported, this can use that instead of munging the SDP. ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
auto offer = caller->CreateOffer();
auto contents = offer->description()->contents();
ASSERT_EQ(1u, contents.size());
auto& stream_params = contents[0].media_description()->mutable_streams();
ASSERT_EQ(1u, stream_params.size());
stream_params[0].set_stream_ids({"stream2"});
ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
ASSERT_EQ(1u, transceiver->receiver()->streams().size()); ASSERT_EQ(1u, transceiver->receiver()->streams().size());
EXPECT_EQ("stream2", transceiver->receiver()->streams()[0]->id()); EXPECT_EQ("stream2", transceiver->receiver()->streams()[0]->id());
} }
@ -1797,12 +1790,7 @@ TEST_P(PeerConnectionRtpTest, CreateTwoSendersWithSameTrack) {
// This test exercises the code path that fires a NegotiationNeeded // This test exercises the code path that fires a NegotiationNeeded
// notification when the stream IDs of the local description differ from // notification when the stream IDs of the local description differ from
// the ones in the transceiver. Since SetStreams() is not yet available // the ones in the transceiver.
// 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, TEST_F(PeerConnectionRtpTestUnifiedPlan,
ChangeAssociatedStreamsTriggersRenegotiation) { ChangeAssociatedStreamsTriggersRenegotiation) {
auto caller = CreatePeerConnection(); auto caller = CreatePeerConnection();
@ -1817,18 +1805,15 @@ TEST_F(PeerConnectionRtpTestUnifiedPlan,
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get())); ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
caller->observer()->clear_negotiation_needed(); caller->observer()->clear_negotiation_needed();
SessionDescriptionInterface* cld = const_cast<SessionDescriptionInterface*>( transceiver->sender()->SetStreamIDs({"stream3", "stream4", "stream5"});
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()); EXPECT_TRUE(caller->observer()->negotiation_needed());
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
auto callee_streams = callee->pc()->GetReceivers()[0]->streams();
ASSERT_EQ(3u, callee_streams.size());
EXPECT_EQ("stream3", callee_streams[0]->id());
EXPECT_EQ("stream4", callee_streams[1]->id());
EXPECT_EQ("stream5", callee_streams[2]->id());
} }
INSTANTIATE_TEST_SUITE_P(PeerConnectionRtpTest, INSTANTIATE_TEST_SUITE_P(PeerConnectionRtpTest,

View file

@ -16,6 +16,7 @@
#include "api/audio_options.h" #include "api/audio_options.h"
#include "api/media_stream_interface.h" #include "api/media_stream_interface.h"
#include "media/base/media_engine.h" #include "media/base/media_engine.h"
#include "pc/peer_connection.h"
#include "pc/stats_collector.h" #include "pc/stats_collector.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/helpers.h" #include "rtc_base/helpers.h"
@ -118,8 +119,12 @@ bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
return false; return false;
} }
RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread, const std::string& id) RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread,
: worker_thread_(worker_thread), id_(id) { const std::string& id,
SetStreamIDsObserver* set_stream_ids_observer)
: worker_thread_(worker_thread),
id_(id),
set_stream_ids_observer_(set_stream_ids_observer) {
RTC_DCHECK(worker_thread); RTC_DCHECK(worker_thread);
init_parameters_.encodings.emplace_back(); init_parameters_.encodings.emplace_back();
} }
@ -215,6 +220,12 @@ RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
return result; return result;
} }
void RtpSenderBase::SetStreamIDs(const std::vector<std::string>& stream_ids) {
stream_ids_ = stream_ids;
if (set_stream_ids_observer_)
set_stream_ids_observer_->OnSetStreamIDs();
}
bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) { bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack"); TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack");
if (stopped_) { if (stopped_) {
@ -317,6 +328,7 @@ void RtpSenderBase::Stop() {
RemoveTrackFromStats(); RemoveTrackFromStats();
} }
media_channel_ = nullptr; media_channel_ = nullptr;
set_stream_ids_observer_ = nullptr;
stopped_ = true; stopped_ = true;
} }
@ -395,15 +407,18 @@ void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create( rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create(
rtc::Thread* worker_thread, rtc::Thread* worker_thread,
const std::string& id, const std::string& id,
StatsCollector* stats) { StatsCollector* stats,
SetStreamIDsObserver* set_stream_ids_observer) {
return rtc::scoped_refptr<AudioRtpSender>( return rtc::scoped_refptr<AudioRtpSender>(
new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats)); new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats,
set_stream_ids_observer));
} }
AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread, AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
const std::string& id, const std::string& id,
StatsCollector* stats) StatsCollector* stats,
: RtpSenderBase(worker_thread, id), SetStreamIDsObserver* set_stream_ids_observer)
: RtpSenderBase(worker_thread, id, set_stream_ids_observer),
stats_(stats), stats_(stats),
dtmf_sender_proxy_(DtmfSenderProxy::Create( dtmf_sender_proxy_(DtmfSenderProxy::Create(
rtc::Thread::Current(), rtc::Thread::Current(),
@ -539,14 +554,17 @@ void AudioRtpSender::ClearSend() {
rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create( rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create(
rtc::Thread* worker_thread, rtc::Thread* worker_thread,
const std::string& id) { const std::string& id,
SetStreamIDsObserver* set_stream_ids_observer) {
return rtc::scoped_refptr<VideoRtpSender>( return rtc::scoped_refptr<VideoRtpSender>(
new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id)); new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id,
set_stream_ids_observer));
} }
VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread, VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
const std::string& id) const std::string& id,
: RtpSenderBase(worker_thread, id) {} SetStreamIDsObserver* set_stream_ids_observer)
: RtpSenderBase(worker_thread, id, set_stream_ids_observer) {}
VideoRtpSender::~VideoRtpSender() { VideoRtpSender::~VideoRtpSender() {
Stop(); Stop();

View file

@ -47,7 +47,7 @@ class RtpSenderInternal : public RtpSenderInterface {
// description). // description).
virtual void SetSsrc(uint32_t ssrc) = 0; virtual void SetSsrc(uint32_t ssrc) = 0;
virtual void set_stream_ids(const std::vector<std::string>& stream_ids) = 0; virtual void SetStreamIDs(const std::vector<std::string>& stream_ids) {}
virtual void set_init_send_encodings( virtual void set_init_send_encodings(
const std::vector<RtpEncodingParameters>& init_send_encodings) = 0; const std::vector<RtpEncodingParameters>& init_send_encodings) = 0;
virtual void set_transport( virtual void set_transport(
@ -74,6 +74,12 @@ class RtpSenderInternal : public RtpSenderInterface {
// Shared implementation for RtpSenderInternal interface. // Shared implementation for RtpSenderInternal interface.
class RtpSenderBase : public RtpSenderInternal, public ObserverInterface { class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
public: public:
class SetStreamIDsObserver {
public:
virtual ~SetStreamIDsObserver() = default;
virtual void OnSetStreamIDs() = 0;
};
// Sets the underlying MediaEngine channel associated with this RtpSender. // Sets the underlying MediaEngine channel associated with this RtpSender.
// A VoiceMediaChannel should be used for audio RtpSenders and // A VoiceMediaChannel should be used for audio RtpSenders and
// a VideoMediaChannel should be used for video RtpSenders. // a VideoMediaChannel should be used for video RtpSenders.
@ -101,9 +107,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
uint32_t ssrc() const override { return ssrc_; } uint32_t ssrc() const override { return ssrc_; }
std::vector<std::string> stream_ids() const override { return stream_ids_; } std::vector<std::string> stream_ids() const override { return stream_ids_; }
void set_stream_ids(const std::vector<std::string>& stream_ids) override { void SetStreamIDs(const std::vector<std::string>& stream_ids) override;
stream_ids_ = stream_ids;
}
std::string id() const override { return id_; } std::string id() const override { return id_; }
@ -143,7 +147,12 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
RTCError DisableEncodingLayers(const std::vector<std::string>& rid) override; RTCError DisableEncodingLayers(const std::vector<std::string>& rid) override;
protected: protected:
RtpSenderBase(rtc::Thread* worker_thread, const std::string& id); // If |set_stream_ids_observer| is not null, it is invoked when SetStreamIDs
// is called. |set_stream_ids_observer| is not owned by this object. If not
// null, it must be valid at least until this sender becomes stopped.
RtpSenderBase(rtc::Thread* worker_thread,
const std::string& id,
SetStreamIDsObserver* set_stream_ids_observer);
// TODO(nisse): Since SSRC == 0 is technically valid, figure out // TODO(nisse): Since SSRC == 0 is technically valid, figure out
// some other way to test if we have a valid SSRC. // some other way to test if we have a valid SSRC.
bool can_send_track() const { return track_ && ssrc_; } bool can_send_track() const { return track_ && ssrc_; }
@ -183,6 +192,8 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
// const method. // const method.
mutable absl::optional<std::string> last_transaction_id_; mutable absl::optional<std::string> last_transaction_id_;
std::vector<std::string> disabled_rids_; std::vector<std::string> disabled_rids_;
SetStreamIDsObserver* set_stream_ids_observer_ = nullptr;
}; };
// LocalAudioSinkAdapter receives data callback as a sink to the local // LocalAudioSinkAdapter receives data callback as a sink to the local
@ -215,9 +226,14 @@ class AudioRtpSender : public DtmfProviderInterface, public RtpSenderBase {
// The sender is initialized with no track to send and no associated streams. // The sender is initialized with no track to send and no associated streams.
// StatsCollector provided so that Add/RemoveLocalAudioTrack can be called // StatsCollector provided so that Add/RemoveLocalAudioTrack can be called
// at the appropriate times. // at the appropriate times.
static rtc::scoped_refptr<AudioRtpSender> Create(rtc::Thread* worker_thread, // If |set_stream_ids_observer| is not null, it is invoked when SetStreamIDs
// is called. |set_stream_ids_observer| is not owned by this object. If not
// null, it must be valid at least until this sender becomes stopped.
static rtc::scoped_refptr<AudioRtpSender> Create(
rtc::Thread* worker_thread,
const std::string& id, const std::string& id,
StatsCollector* stats); StatsCollector* stats,
SetStreamIDsObserver* set_stream_ids_observer);
virtual ~AudioRtpSender(); virtual ~AudioRtpSender();
// DtmfSenderProvider implementation. // DtmfSenderProvider implementation.
@ -240,7 +256,8 @@ class AudioRtpSender : public DtmfProviderInterface, public RtpSenderBase {
protected: protected:
AudioRtpSender(rtc::Thread* worker_thread, AudioRtpSender(rtc::Thread* worker_thread,
const std::string& id, const std::string& id,
StatsCollector* stats); StatsCollector* stats,
SetStreamIDsObserver* set_stream_ids_observer);
void SetSend() override; void SetSend() override;
void ClearSend() override; void ClearSend() override;
@ -274,8 +291,13 @@ class VideoRtpSender : public RtpSenderBase {
public: public:
// Construct an RtpSender for video with the given sender ID. // Construct an RtpSender for video with the given sender ID.
// The sender is initialized with no track to send and no associated streams. // The sender is initialized with no track to send and no associated streams.
static rtc::scoped_refptr<VideoRtpSender> Create(rtc::Thread* worker_thread, // If |set_stream_ids_observer| is not null, it is invoked when SetStreamIDs
const std::string& id); // is called. |set_stream_ids_observer| is not owned by this object. If not
// null, it must be valid at least until this sender becomes stopped.
static rtc::scoped_refptr<VideoRtpSender> Create(
rtc::Thread* worker_thread,
const std::string& id,
SetStreamIDsObserver* set_stream_ids_observer);
virtual ~VideoRtpSender(); virtual ~VideoRtpSender();
// ObserverInterface implementation // ObserverInterface implementation
@ -291,7 +313,9 @@ class VideoRtpSender : public RtpSenderBase {
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override; rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
protected: protected:
VideoRtpSender(rtc::Thread* worker_thread, const std::string& id); VideoRtpSender(rtc::Thread* worker_thread,
const std::string& id,
SetStreamIDsObserver* set_stream_ids_observer);
void SetSend() override; void SetSend() override;
void ClearSend() override; void ClearSend() override;

View file

@ -83,6 +83,13 @@ static const uint32_t kAudioSsrc2 = 101;
static const uint32_t kVideoSsrcSimulcast = 102; static const uint32_t kVideoSsrcSimulcast = 102;
static const uint32_t kVideoSimulcastLayerCount = 2; static const uint32_t kVideoSimulcastLayerCount = 2;
static const int kDefaultTimeout = 10000; // 10 seconds. static const int kDefaultTimeout = 10000; // 10 seconds.
class MockSetStreamIDsObserver
: public webrtc::RtpSenderBase::SetStreamIDsObserver {
public:
MOCK_METHOD0(OnSetStreamIDs, void());
};
} // namespace } // namespace
namespace webrtc { namespace webrtc {
@ -187,10 +194,14 @@ class RtpSenderReceiverTest
const rtc::scoped_refptr<LocalAudioSource>& source) { const rtc::scoped_refptr<LocalAudioSource>& source) {
audio_track_ = AudioTrack::Create(kAudioTrackId, source); audio_track_ = AudioTrack::Create(kAudioTrackId, source);
EXPECT_TRUE(local_stream_->AddTrack(audio_track_)); EXPECT_TRUE(local_stream_->AddTrack(audio_track_));
std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
absl::make_unique<MockSetStreamIDsObserver>();
audio_rtp_sender_ = audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, audio_track_->id(), nullptr); AudioRtpSender::Create(worker_thread_, audio_track_->id(), nullptr,
set_stream_ids_observer.get());
ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_)); ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_));
audio_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
audio_rtp_sender_->SetStreamIDs({local_stream_->id()});
audio_rtp_sender_->SetMediaChannel(voice_media_channel_); audio_rtp_sender_->SetMediaChannel(voice_media_channel_);
audio_rtp_sender_->SetSsrc(kAudioSsrc); audio_rtp_sender_->SetSsrc(kAudioSsrc);
audio_rtp_sender_->GetOnDestroyedSignal()->connect( audio_rtp_sender_->GetOnDestroyedSignal()->connect(
@ -200,7 +211,7 @@ class RtpSenderReceiverTest
void CreateAudioRtpSenderWithNoTrack() { void CreateAudioRtpSenderWithNoTrack() {
audio_rtp_sender_ = audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr); AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
audio_rtp_sender_->SetMediaChannel(voice_media_channel_); audio_rtp_sender_->SetMediaChannel(voice_media_channel_);
} }
@ -248,16 +259,20 @@ class RtpSenderReceiverTest
void CreateVideoRtpSender(bool is_screencast, uint32_t ssrc = kVideoSsrc) { void CreateVideoRtpSender(bool is_screencast, uint32_t ssrc = kVideoSsrc) {
AddVideoTrack(is_screencast); AddVideoTrack(is_screencast);
video_rtp_sender_ = std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
VideoRtpSender::Create(worker_thread_, video_track_->id()); absl::make_unique<MockSetStreamIDsObserver>();
video_rtp_sender_ = VideoRtpSender::Create(
worker_thread_, video_track_->id(), set_stream_ids_observer.get());
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_)); ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
video_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
video_rtp_sender_->SetStreamIDs({local_stream_->id()});
video_rtp_sender_->SetMediaChannel(video_media_channel_); video_rtp_sender_->SetMediaChannel(video_media_channel_);
video_rtp_sender_->SetSsrc(ssrc); video_rtp_sender_->SetSsrc(ssrc);
VerifyVideoChannelInput(ssrc); VerifyVideoChannelInput(ssrc);
} }
void CreateVideoRtpSenderWithNoTrack() { void CreateVideoRtpSenderWithNoTrack() {
video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, /*id=*/""); video_rtp_sender_ =
VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
video_rtp_sender_->SetMediaChannel(video_media_channel_); video_rtp_sender_->SetMediaChannel(video_media_channel_);
} }
@ -428,7 +443,7 @@ class RtpSenderReceiverTest
void RunDisableSimulcastLayersWithoutMediaEngineTest( void RunDisableSimulcastLayersWithoutMediaEngineTest(
const std::vector<std::string>& all_layers, const std::vector<std::string>& all_layers,
const std::vector<std::string>& disabled_layers) { const std::vector<std::string>& disabled_layers) {
auto sender = VideoRtpSender::Create(rtc::Thread::Current(), "1"); auto sender = VideoRtpSender::Create(rtc::Thread::Current(), "1", nullptr);
RtpParameters parameters; RtpParameters parameters;
parameters.encodings.resize(all_layers.size()); parameters.encodings.resize(all_layers.size());
for (size_t i = 0; i < all_layers.size(); ++i) { for (size_t i = 0; i < all_layers.size(); ++i) {
@ -820,7 +835,7 @@ TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParameters) {
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) { TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) {
audio_rtp_sender_ = audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr); AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
RtpParameters params = audio_rtp_sender_->GetParameters(); RtpParameters params = audio_rtp_sender_->GetParameters();
ASSERT_EQ(1u, params.encodings.size()); ASSERT_EQ(1u, params.encodings.size());
@ -838,10 +853,14 @@ TEST_F(RtpSenderReceiverTest, AudioSenderInitParametersMovedAfterNegotiation) {
audio_track_ = AudioTrack::Create(kAudioTrackId, nullptr); audio_track_ = AudioTrack::Create(kAudioTrackId, nullptr);
EXPECT_TRUE(local_stream_->AddTrack(audio_track_)); EXPECT_TRUE(local_stream_->AddTrack(audio_track_));
std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
absl::make_unique<MockSetStreamIDsObserver>();
audio_rtp_sender_ = audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, audio_track_->id(), nullptr); AudioRtpSender::Create(worker_thread_, audio_track_->id(), nullptr,
set_stream_ids_observer.get());
ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_)); ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_));
audio_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
audio_rtp_sender_->SetStreamIDs({local_stream_->id()});
std::vector<RtpEncodingParameters> init_encodings(1); std::vector<RtpEncodingParameters> init_encodings(1);
init_encodings[0].max_bitrate_bps = 60000; init_encodings[0].max_bitrate_bps = 60000;
@ -869,7 +888,7 @@ TEST_F(RtpSenderReceiverTest, AudioSenderInitParametersMovedAfterNegotiation) {
TEST_F(RtpSenderReceiverTest, TEST_F(RtpSenderReceiverTest,
AudioSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) { AudioSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) {
audio_rtp_sender_ = audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr); AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
RtpParameters params; RtpParameters params;
RTCError result = audio_rtp_sender_->SetParameters(params); RTCError result = audio_rtp_sender_->SetParameters(params);
@ -1048,7 +1067,8 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParameters) {
} }
TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) { TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, /*id=*/""); video_rtp_sender_ =
VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
RtpParameters params = video_rtp_sender_->GetParameters(); RtpParameters params = video_rtp_sender_->GetParameters();
ASSERT_EQ(1u, params.encodings.size()); ASSERT_EQ(1u, params.encodings.size());
@ -1065,10 +1085,13 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
TEST_F(RtpSenderReceiverTest, VideoSenderInitParametersMovedAfterNegotiation) { TEST_F(RtpSenderReceiverTest, VideoSenderInitParametersMovedAfterNegotiation) {
AddVideoTrack(false); AddVideoTrack(false);
video_rtp_sender_ = std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
VideoRtpSender::Create(worker_thread_, video_track_->id()); absl::make_unique<MockSetStreamIDsObserver>();
video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, video_track_->id(),
set_stream_ids_observer.get());
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_)); ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
video_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
video_rtp_sender_->SetStreamIDs({local_stream_->id()});
std::vector<RtpEncodingParameters> init_encodings(2); std::vector<RtpEncodingParameters> init_encodings(2);
init_encodings[0].max_bitrate_bps = 60000; init_encodings[0].max_bitrate_bps = 60000;
@ -1103,10 +1126,13 @@ TEST_F(RtpSenderReceiverTest,
VideoSenderInitParametersMovedAfterManualSimulcastAndNegotiation) { VideoSenderInitParametersMovedAfterManualSimulcastAndNegotiation) {
AddVideoTrack(false); AddVideoTrack(false);
video_rtp_sender_ = std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
VideoRtpSender::Create(worker_thread_, video_track_->id()); absl::make_unique<MockSetStreamIDsObserver>();
video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, video_track_->id(),
set_stream_ids_observer.get());
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_)); ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
video_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
video_rtp_sender_->SetStreamIDs({local_stream_->id()});
std::vector<RtpEncodingParameters> init_encodings(1); std::vector<RtpEncodingParameters> init_encodings(1);
init_encodings[0].max_bitrate_bps = 60000; init_encodings[0].max_bitrate_bps = 60000;
@ -1137,7 +1163,8 @@ TEST_F(RtpSenderReceiverTest,
TEST_F(RtpSenderReceiverTest, TEST_F(RtpSenderReceiverTest,
VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) { VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) {
video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, /*id=*/""); video_rtp_sender_ =
VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
RtpParameters params; RtpParameters params;
RTCError result = video_rtp_sender_->SetParameters(params); RTCError result = video_rtp_sender_->SetParameters(params);
@ -1527,13 +1554,16 @@ TEST_F(RtpSenderReceiverTest,
TEST_F(RtpSenderReceiverTest, TEST_F(RtpSenderReceiverTest,
PropagatesVideoTrackContentHintSetBeforeEnabling) { PropagatesVideoTrackContentHintSetBeforeEnabling) {
AddVideoTrack(); AddVideoTrack();
std::unique_ptr<MockSetStreamIDsObserver> set_stream_ids_observer =
absl::make_unique<MockSetStreamIDsObserver>();
// Setting detailed overrides the default non-screencast mode. This should be // Setting detailed overrides the default non-screencast mode. This should be
// applied even if the track is set on construction. // applied even if the track is set on construction.
video_track_->set_content_hint(VideoTrackInterface::ContentHint::kDetailed); video_track_->set_content_hint(VideoTrackInterface::ContentHint::kDetailed);
video_rtp_sender_ = video_rtp_sender_ = VideoRtpSender::Create(worker_thread_, video_track_->id(),
VideoRtpSender::Create(worker_thread_, video_track_->id()); set_stream_ids_observer.get());
ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_)); ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_));
video_rtp_sender_->set_stream_ids({local_stream_->id()}); EXPECT_CALL(*set_stream_ids_observer, OnSetStreamIDs());
video_rtp_sender_->SetStreamIDs({local_stream_->id()});
video_rtp_sender_->SetMediaChannel(video_media_channel_); video_rtp_sender_->SetMediaChannel(video_media_channel_);
video_track_->set_enabled(true); video_track_->set_enabled(true);

View file

@ -46,7 +46,7 @@ class MockRtpSenderInternal : public RtpSenderInternal {
// RtpSenderInternal methods. // RtpSenderInternal methods.
MOCK_METHOD1(SetMediaChannel, void(cricket::MediaChannel*)); MOCK_METHOD1(SetMediaChannel, void(cricket::MediaChannel*));
MOCK_METHOD1(SetSsrc, void(uint32_t)); MOCK_METHOD1(SetSsrc, void(uint32_t));
MOCK_METHOD1(set_stream_ids, void(const std::vector<std::string>&)); MOCK_METHOD1(SetStreamIDs, void(const std::vector<std::string>&));
MOCK_METHOD1(set_init_send_encodings, MOCK_METHOD1(set_init_send_encodings,
void(const std::vector<RtpEncodingParameters>&)); void(const std::vector<RtpEncodingParameters>&));
MOCK_METHOD0(Stop, void()); MOCK_METHOD0(Stop, void());