Reland "Add AddTransceiver and GetTransceivers to PeerConnection"
This reverts commit 8b13f96e2d4b0449e54a3665121a4302ceb56e80.
Original change's description:
> Revert "Add AddTransceiver and GetTransceivers to PeerConnection"
>
> This reverts commit f93d2800d9b0d5818a5a383def0aaef3d441df3a.
>
> Reason for revert: https://logs.chromium.org/v/?s=chromium%2Fbb%2Fchromium.webrtc.fyi%2Fios-device%2F5804%2F%2B%2Frecipes%2Fsteps%2Fcompile%2F0%2Fstdout
>
> Original change's description:
> > Add AddTransceiver and GetTransceivers to PeerConnection
> >
> > WebRTC 1.0 has added the transceiver API to PeerConnection. This
> > is the first step towards exposing this to WebRTC consumers. For
> > now, transceivers can be added and fetched but there is not yet
> > support for creating offers/answers or setting local/remote
> > descriptions. That support ("Unified Plan") will be added in
> > follow-up CLs.
> >
> > The transceiver API is currently only available if the application
> > opts in by specifying the kUnifiedPlan SDP semantics when creating
> > the PeerConnection.
> >
> > Bug: webrtc:7600
> > Change-Id: I0b8ee24b489b45bb4c5f60b699bd20c61af01d8e
> > Reviewed-on: https://webrtc-review.googlesource.com/23880
> > Commit-Queue: Steve Anton <steveanton@webrtc.org>
> > Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
> > Reviewed-by: Henrik Boström <hbos@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#20896}
>
> TBR=steveanton@webrtc.org,zhihuang@webrtc.org,hbos@webrtc.org,pthatcher@webrtc.org
>
> Change-Id: Ie91ea4988dba25c20e2532114d3a9d859a932d4c
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: webrtc:7600
> Reviewed-on: https://webrtc-review.googlesource.com/26400
> Reviewed-by: Steve Anton <steveanton@webrtc.org>
> Commit-Queue: Steve Anton <steveanton@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#20897}
TBR=steveanton@webrtc.org,zhihuang@webrtc.org,hbos@webrtc.org,pthatcher@webrtc.org
Change-Id: I19fdf08c54f09302794e998a0ffddb82ae0d7b41
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:7600
Reviewed-on: https://webrtc-review.googlesource.com/26401
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20898}
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index a7b4ef6..a1e7d7e 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -82,6 +82,7 @@
#include "api/rtceventlogoutput.h"
#include "api/rtpreceiverinterface.h"
#include "api/rtpsenderinterface.h"
+#include "api/rtptransceiverinterface.h"
#include "api/setremotedescriptionobserverinterface.h"
#include "api/stats/rtcstatscollectorcallback.h"
#include "api/statstypes.h"
@@ -601,6 +602,57 @@
// Returns true on success.
virtual bool RemoveTrack(RtpSenderInterface* sender) = 0;
+ // AddTransceiver creates a new RtpTransceiver and adds it to the set of
+ // transceivers. Adding a transceiver will cause future calls to CreateOffer
+ // to add a media description for the corresponding transceiver.
+ //
+ // The initial value of |mid| in the returned transceiver is null. Setting a
+ // new session description may change it to a non-null value.
+ //
+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
+ //
+ // Optionally, an RtpTransceiverInit structure can be specified to configure
+ // the transceiver from construction. If not specified, the transceiver will
+ // default to having a direction of kSendRecv and not be part of any streams.
+ //
+ // These methods are only available when Unified Plan is enabled (see
+ // RTCConfiguration).
+ //
+ // Common errors:
+ // - INTERNAL_ERROR: The configuration does not have Unified Plan enabled.
+ // TODO(steveanton): Make these pure virtual once downstream projects have
+ // updated.
+
+ // Adds a transceiver with a sender set to transmit the given track. The kind
+ // of the transceiver (and sender/receiver) will be derived from the kind of
+ // the track.
+ // Errors:
+ // - INVALID_PARAMETER: |track| is null.
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+ }
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+ }
+
+ // Adds a transceiver with the given kind. Can either be MEDIA_TYPE_AUDIO or
+ // MEDIA_TYPE_VIDEO.
+ // Errors:
+ // - INVALID_PARAMETER: |media_type| is not MEDIA_TYPE_AUDIO or
+ // MEDIA_TYPE_VIDEO.
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(cricket::MediaType media_type) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+ }
+ virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+ AddTransceiver(cricket::MediaType media_type,
+ const RtpTransceiverInit& init) {
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
+ }
+
// Returns pointer to a DtmfSender on success. Otherwise returns null.
//
// This API is no longer part of the standard; instead DtmfSenders are
@@ -650,6 +702,15 @@
return std::vector<rtc::scoped_refptr<RtpReceiverInterface>>();
}
+ // Get all RtpTransceivers, created either through AddTransceiver, AddTrack or
+ // by a remote description applied with SetRemoteDescription.
+ // Note: This method is only available when Unified Plan is enabled (see
+ // RTCConfiguration).
+ virtual std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
+ GetTransceivers() const {
+ return {};
+ }
+
virtual bool GetStats(StatsObserver* observer,
MediaStreamTrackInterface* track,
StatsOutputLevel level) = 0;
diff --git a/api/peerconnectionproxy.h b/api/peerconnectionproxy.h
index bdd9fcb..1d8cf5f 100644
--- a/api/peerconnectionproxy.h
+++ b/api/peerconnectionproxy.h
@@ -33,6 +33,20 @@
MediaStreamTrackInterface*,
std::vector<MediaStreamInterface*>)
PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*)
+ PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ rtc::scoped_refptr<MediaStreamTrackInterface>)
+ PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ rtc::scoped_refptr<MediaStreamTrackInterface>,
+ const RtpTransceiverInit&)
+ PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ cricket::MediaType)
+ PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ AddTransceiver,
+ cricket::MediaType,
+ const RtpTransceiverInit&)
PROXY_METHOD1(rtc::scoped_refptr<DtmfSenderInterface>,
CreateDtmfSender,
AudioTrackInterface*)
@@ -44,6 +58,8 @@
GetSenders)
PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
GetReceivers)
+ PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
+ GetTransceivers)
PROXY_METHOD3(bool,
GetStats,
StatsObserver*,
diff --git a/api/rtptransceiverinterface.h b/api/rtptransceiverinterface.h
index 3eb246a..88607b2 100644
--- a/api/rtptransceiverinterface.h
+++ b/api/rtptransceiverinterface.h
@@ -12,6 +12,7 @@
#define API_RTPTRANSCEIVERINTERFACE_H_
#include <string>
+#include <vector>
#include "api/optional.h"
#include "api/rtpreceiverinterface.h"
@@ -20,6 +21,7 @@
namespace webrtc {
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection
enum class RtpTransceiverDirection {
kSendRecv,
kSendOnly,
@@ -27,6 +29,21 @@
kInactive
};
+// Structure for initializing an RtpTransceiver in a call to
+// PeerConnectionInterface::AddTransceiver.
+// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
+struct RtpTransceiverInit final {
+ // Direction of the RtpTransceiver. See RtpTransceiverInterface::direction().
+ RtpTransceiverDirection direction = RtpTransceiverDirection::kSendRecv;
+
+ // The added RtpTransceiver will be added to these streams.
+ // TODO(bugs.webrtc.org/7600): Not implemented.
+ std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
+
+ // TODO(bugs.webrtc.org/7600): Not implemented.
+ std::vector<RtpEncodingParameters> send_encodings;
+};
+
// The RtpTransceiverInterface maps to the RTCRtpTransceiver defined by the
// WebRTC specification. A transceiver represents a combination of an RtpSender
// and an RtpReceiver than share a common mid. As defined in JSEP, an
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 65eb603..2c6cc4b 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -1205,6 +1205,110 @@
return true;
}
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track) {
+ return AddTransceiver(track, RtpTransceiverInit());
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) {
+ if (!IsUnifiedPlan()) {
+ LOG_AND_RETURN_ERROR(
+ RTCErrorType::INTERNAL_ERROR,
+ "AddTransceiver only supported when Unified Plan is enabled.");
+ }
+ if (!track) {
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "track is null");
+ }
+ cricket::MediaType media_type;
+ if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
+ media_type = cricket::MEDIA_TYPE_AUDIO;
+ } else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
+ media_type = cricket::MEDIA_TYPE_VIDEO;
+ } else {
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+ "Track kind is not audio or video");
+ }
+ return AddTransceiver(media_type, track, init);
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::AddTransceiver(cricket::MediaType media_type) {
+ return AddTransceiver(media_type, RtpTransceiverInit());
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::AddTransceiver(cricket::MediaType media_type,
+ const RtpTransceiverInit& init) {
+ if (!IsUnifiedPlan()) {
+ LOG_AND_RETURN_ERROR(
+ RTCErrorType::INTERNAL_ERROR,
+ "AddTransceiver only supported when Unified Plan is enabled.");
+ }
+ if (!(media_type == cricket::MEDIA_TYPE_AUDIO ||
+ media_type == cricket::MEDIA_TYPE_VIDEO)) {
+ LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+ "media type is not audio or video");
+ }
+ return AddTransceiver(media_type, nullptr, init);
+}
+
+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::AddTransceiver(
+ cricket::MediaType media_type,
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) {
+ RTC_DCHECK((media_type == cricket::MEDIA_TYPE_AUDIO ||
+ media_type == cricket::MEDIA_TYPE_VIDEO));
+ if (track) {
+ RTC_DCHECK_EQ(media_type,
+ (track->kind() == MediaStreamTrackInterface::kAudioKind
+ ? cricket::MEDIA_TYPE_AUDIO
+ : cricket::MEDIA_TYPE_VIDEO));
+ }
+
+ // TODO(bugs.webrtc.org/7600): Verify init.
+
+ rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
+ rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
+ receiver;
+ std::string receiver_id = rtc::CreateRandomUuid();
+ if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+ sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
+ signaling_thread(), new AudioRtpSender(nullptr, stats_.get()));
+ receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+ signaling_thread(), new AudioRtpReceiver(receiver_id, {}, 0, nullptr));
+ } else {
+ RTC_DCHECK_EQ(cricket::MEDIA_TYPE_VIDEO, media_type);
+ sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
+ signaling_thread(), new VideoRtpSender(nullptr));
+ receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
+ signaling_thread(),
+ new VideoRtpReceiver(receiver_id, {}, worker_thread(), 0, nullptr));
+ }
+ // TODO(bugs.webrtc.org/7600): Initializing the sender/receiver with a null
+ // channel prevents users from calling SetParameters on them, which is needed
+ // to be in compliance with the spec.
+
+ if (track) {
+ sender->SetTrack(track);
+ }
+
+ rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
+ transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
+ signaling_thread(), new RtpTransceiver(sender, receiver));
+ transceiver->SetDirection(init.direction);
+
+ transceivers_.push_back(transceiver);
+
+ observer_->OnRenegotiationNeeded();
+
+ return rtc::scoped_refptr<RtpTransceiverInterface>(transceiver);
+}
+
rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
AudioTrackInterface* track) {
TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
@@ -1297,6 +1401,16 @@
return all_receivers;
}
+std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
+PeerConnection::GetTransceivers() const {
+ RTC_DCHECK(IsUnifiedPlan());
+ std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> all_transceivers;
+ for (auto transceiver : transceivers_) {
+ all_transceivers.push_back(transceiver);
+ }
+ return all_transceivers;
+}
+
bool PeerConnection::GetStats(StatsObserver* observer,
MediaStreamTrackInterface* track,
StatsOutputLevel level) {
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index 2bbce48..d262ede 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -94,6 +94,17 @@
std::vector<MediaStreamInterface*> streams) override;
bool RemoveTrack(RtpSenderInterface* sender) override;
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track) override;
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) override;
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
+ cricket::MediaType media_type) override;
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
+ cricket::MediaType media_type,
+ const RtpTransceiverInit& init) override;
+
// Gets the DTLS SSL certificate associated with the audio transport on the
// remote side. This will become populated once the DTLS connection with the
// peer has been completed, as indicated by the ICE connection state
@@ -114,6 +125,8 @@
const override;
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers()
const override;
+ std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> GetTransceivers()
+ const override;
rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
const std::string& label,
@@ -327,6 +340,11 @@
void RemoveVideoTrack(VideoTrackInterface* track,
MediaStreamInterface* stream);
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
+ cricket::MediaType media_type,
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init);
+
void SetIceConnectionState(IceConnectionState new_state);
// Called any time the IceGatheringState changes
void OnIceGatheringChange(IceGatheringState new_state);
diff --git a/pc/peerconnection_rtp_unittest.cc b/pc/peerconnection_rtp_unittest.cc
index 0421124..e7ac8c7 100644
--- a/pc/peerconnection_rtp_unittest.cc
+++ b/pc/peerconnection_rtp_unittest.cc
@@ -27,11 +27,16 @@
#include "rtc_base/refcountedobject.h"
#include "rtc_base/scoped_ref_ptr.h"
#include "rtc_base/thread.h"
+#include "test/gmock.h"
// This file contains tests for RTP Media API-related behavior of
// |webrtc::PeerConnection|, see https://w3c.github.io/webrtc-pc/#rtp-media-api.
-namespace {
+namespace webrtc {
+
+using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
+using ::testing::ElementsAre;
+using ::testing::UnorderedElementsAre;
const uint32_t kDefaultTimeout = 10000u;
@@ -55,28 +60,37 @@
class PeerConnectionRtpTest : public testing::Test {
public:
PeerConnectionRtpTest()
- : pc_factory_(webrtc::CreatePeerConnectionFactory(
- rtc::Thread::Current(),
- rtc::Thread::Current(),
- rtc::Thread::Current(),
- FakeAudioCaptureModule::Create(),
- webrtc::CreateBuiltinAudioEncoderFactory(),
- webrtc::CreateBuiltinAudioDecoderFactory(),
- nullptr,
- nullptr)) {}
+ : pc_factory_(
+ CreatePeerConnectionFactory(rtc::Thread::Current(),
+ rtc::Thread::Current(),
+ rtc::Thread::Current(),
+ FakeAudioCaptureModule::Create(),
+ CreateBuiltinAudioEncoderFactory(),
+ CreateBuiltinAudioDecoderFactory(),
+ nullptr,
+ nullptr)) {}
- std::unique_ptr<webrtc::PeerConnectionWrapper> CreatePeerConnection() {
- webrtc::PeerConnectionInterface::RTCConfiguration config;
- auto observer = rtc::MakeUnique<webrtc::MockPeerConnectionObserver>();
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection() {
+ return CreatePeerConnection(RTCConfiguration());
+ }
+
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWithUnifiedPlan() {
+ RTCConfiguration config;
+ config.sdp_semantics = SdpSemantics::kUnifiedPlan;
+ return CreatePeerConnection(config);
+ }
+
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection(
+ const RTCConfiguration& config) {
+ auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr,
observer.get());
- return std::unique_ptr<webrtc::PeerConnectionWrapper>(
- new webrtc::PeerConnectionWrapper(pc_factory_, pc,
- std::move(observer)));
+ return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory_, pc,
+ std::move(observer));
}
protected:
- rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
+ rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
};
// These tests cover |webrtc::PeerConnectionObserver| callbacks firing upon
@@ -87,7 +101,7 @@
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track(
pc_factory_->CreateAudioTrack("audio_track", nullptr));
EXPECT_TRUE(caller->pc()->AddTrack(audio_track.get(), {}));
ASSERT_TRUE(
@@ -107,9 +121,9 @@
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track(
pc_factory_->CreateAudioTrack("audio_track", nullptr));
- auto stream = webrtc::MediaStream::Create("audio_stream");
+ auto stream = MediaStream::Create("audio_stream");
EXPECT_TRUE(caller->pc()->AddTrack(audio_track.get(), {stream.get()}));
ASSERT_TRUE(
callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(),
@@ -128,7 +142,7 @@
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track(
pc_factory_->CreateAudioTrack("audio_track", nullptr));
auto sender = caller->pc()->AddTrack(audio_track.get(), {});
ASSERT_TRUE(
@@ -150,9 +164,9 @@
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track(
pc_factory_->CreateAudioTrack("audio_track", nullptr));
- auto stream = webrtc::MediaStream::Create("audio_stream");
+ auto stream = MediaStream::Create("audio_stream");
auto sender = caller->pc()->AddTrack(audio_track.get(), {stream.get()});
ASSERT_TRUE(
callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(),
@@ -173,12 +187,12 @@
auto caller = CreatePeerConnection();
auto callee = CreatePeerConnection();
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track1(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track1(
pc_factory_->CreateAudioTrack("audio_track1", nullptr));
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track2(
+ rtc::scoped_refptr<AudioTrackInterface> audio_track2(
pc_factory_->CreateAudioTrack("audio_track2", nullptr));
- auto stream = webrtc::MediaStream::Create("shared_audio_stream");
- std::vector<webrtc::MediaStreamInterface*> streams{stream.get()};
+ auto stream = MediaStream::Create("shared_audio_stream");
+ std::vector<MediaStreamInterface*> streams{stream.get()};
auto sender1 = caller->pc()->AddTrack(audio_track1.get(), streams);
auto sender2 = caller->pc()->AddTrack(audio_track2.get(), streams);
ASSERT_TRUE(
@@ -194,7 +208,7 @@
static_cast<webrtc::RTCError*>(nullptr)));
ASSERT_EQ(callee->observer()->add_track_events_.size(), 2u);
EXPECT_EQ(
- std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>{
+ std::vector<rtc::scoped_refptr<RtpReceiverInterface>>{
callee->observer()->add_track_events_[0].receiver},
callee->observer()->remove_track_events_);
@@ -438,4 +452,146 @@
EXPECT_FALSE(observer->called());
}
-} // namespace
+// RtpTransceiver Tests
+
+// Test that by default there are no transceivers with Unified Plan.
+TEST_F(PeerConnectionRtpTest, PeerConnectionHasNoTransceivers) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+ EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
+}
+
+// Test that a transceiver created with the audio kind has the correct initial
+// properties.
+TEST_F(PeerConnectionRtpTest, AddTransceiverHasCorrectInitProperties) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
+ EXPECT_EQ(rtc::nullopt, transceiver->mid());
+ EXPECT_FALSE(transceiver->stopped());
+ EXPECT_EQ(RtpTransceiverDirection::kSendRecv, transceiver->direction());
+ EXPECT_EQ(rtc::nullopt, transceiver->current_direction());
+}
+
+// Test that adding a transceiver with the audio kind creates an audio sender
+// and audio receiver with the receiver having a live audio track.
+TEST_F(PeerConnectionRtpTest,
+ AddAudioTransceiverCreatesAudioSenderAndReceiver) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
+
+ ASSERT_TRUE(transceiver->sender());
+ EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceiver->sender()->media_type());
+
+ ASSERT_TRUE(transceiver->receiver());
+ EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceiver->receiver()->media_type());
+
+ auto track = transceiver->receiver()->track();
+ ASSERT_TRUE(track);
+ EXPECT_EQ(MediaStreamTrackInterface::kAudioKind, track->kind());
+ EXPECT_EQ(MediaStreamTrackInterface::TrackState::kLive, track->state());
+}
+
+// Test that adding a transceiver with the video kind creates an video sender
+// and video receiver with the receiver having a live video track.
+TEST_F(PeerConnectionRtpTest,
+ AddAudioTransceiverCreatesVideoSenderAndReceiver) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
+
+ ASSERT_TRUE(transceiver->sender());
+ EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceiver->sender()->media_type());
+
+ ASSERT_TRUE(transceiver->receiver());
+ EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceiver->receiver()->media_type());
+
+ auto track = transceiver->receiver()->track();
+ ASSERT_TRUE(track);
+ EXPECT_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
+ EXPECT_EQ(MediaStreamTrackInterface::TrackState::kLive, track->state());
+}
+
+// Test that after a call to AddTransceiver, the transceiver shows in
+// GetTransceivers(), the transceiver's sender shows in GetSenders(), and the
+// transceiver's receiver shows in GetReceivers().
+TEST_F(PeerConnectionRtpTest, AddTransceiverShowsInLists) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
+ EXPECT_EQ(
+ std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>{transceiver},
+ caller->pc()->GetTransceivers());
+ EXPECT_EQ(
+ std::vector<rtc::scoped_refptr<RtpSenderInterface>>{
+ transceiver->sender()},
+ caller->pc()->GetSenders());
+ EXPECT_EQ(
+ std::vector<rtc::scoped_refptr<RtpReceiverInterface>>{
+ transceiver->receiver()},
+ caller->pc()->GetReceivers());
+}
+
+// Test that the direction passed in through the AddTransceiver init parameter
+// is set in the returned transceiver.
+TEST_F(PeerConnectionRtpTest, AddTransceiverWithDirectionIsReflected) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ RtpTransceiverInit init;
+ init.direction = RtpTransceiverDirection::kSendOnly;
+ auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
+ EXPECT_EQ(RtpTransceiverDirection::kSendOnly, transceiver->direction());
+}
+
+TEST_F(PeerConnectionRtpTest, AddTransceiverWithInvalidKindReturnsError) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto result = caller->pc()->AddTransceiver(cricket::MEDIA_TYPE_DATA);
+ EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, result.error().type());
+}
+
+// Test that calling AddTransceiver with a track creates a transceiver which has
+// its sender's track set to the passed-in track.
+TEST_F(PeerConnectionRtpTest, AddTransceiverWithTrackCreatesSenderWithTrack) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto audio_track = caller->CreateAudioTrack("audio track");
+ auto transceiver = caller->AddTransceiver(audio_track);
+
+ auto sender = transceiver->sender();
+ ASSERT_TRUE(sender->track());
+ EXPECT_EQ(audio_track, sender->track());
+
+ auto receiver = transceiver->receiver();
+ ASSERT_TRUE(receiver->track());
+ EXPECT_EQ(MediaStreamTrackInterface::kAudioKind, receiver->track()->kind());
+ EXPECT_EQ(MediaStreamTrackInterface::TrackState::kLive,
+ receiver->track()->state());
+}
+
+// Test that calling AddTransceiver twice with the same track creates distinct
+// transceivers, senders with the same track.
+TEST_F(PeerConnectionRtpTest,
+ AddTransceiverTwiceWithSameTrackCreatesMultipleTransceivers) {
+ auto caller = CreatePeerConnectionWithUnifiedPlan();
+
+ auto audio_track = caller->CreateAudioTrack("audio track");
+
+ auto transceiver1 = caller->AddTransceiver(audio_track);
+ auto transceiver2 = caller->AddTransceiver(audio_track);
+
+ EXPECT_NE(transceiver1, transceiver2);
+
+ auto sender1 = transceiver1->sender();
+ auto sender2 = transceiver2->sender();
+ EXPECT_NE(sender1, sender2);
+ EXPECT_EQ(audio_track, sender1->track());
+ EXPECT_EQ(audio_track, sender2->track());
+
+ EXPECT_THAT(caller->pc()->GetTransceivers(),
+ UnorderedElementsAre(transceiver1, transceiver2));
+ EXPECT_THAT(caller->pc()->GetSenders(),
+ UnorderedElementsAre(sender1, sender2));
+}
+
+} // namespace webrtc
diff --git a/pc/peerconnectionwrapper.cc b/pc/peerconnectionwrapper.cc
index 1b92efa..121cc64 100644
--- a/pc/peerconnectionwrapper.cc
+++ b/pc/peerconnectionwrapper.cc
@@ -179,22 +179,64 @@
return observer->result();
}
+rtc::scoped_refptr<RtpTransceiverInterface>
+PeerConnectionWrapper::AddTransceiver(cricket::MediaType media_type) {
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
+ pc()->AddTransceiver(media_type);
+ EXPECT_EQ(RTCErrorType::NONE, result.error().type());
+ return result.MoveValue();
+}
+
+rtc::scoped_refptr<RtpTransceiverInterface>
+PeerConnectionWrapper::AddTransceiver(cricket::MediaType media_type,
+ const RtpTransceiverInit& init) {
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
+ pc()->AddTransceiver(media_type, init);
+ EXPECT_EQ(RTCErrorType::NONE, result.error().type());
+ return result.MoveValue();
+}
+
+rtc::scoped_refptr<RtpTransceiverInterface>
+PeerConnectionWrapper::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track) {
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
+ pc()->AddTransceiver(track);
+ EXPECT_EQ(RTCErrorType::NONE, result.error().type());
+ return result.MoveValue();
+}
+
+rtc::scoped_refptr<RtpTransceiverInterface>
+PeerConnectionWrapper::AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init) {
+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
+ pc()->AddTransceiver(track, init);
+ EXPECT_EQ(RTCErrorType::NONE, result.error().type());
+ return result.MoveValue();
+}
+
+rtc::scoped_refptr<AudioTrackInterface> PeerConnectionWrapper::CreateAudioTrack(
+ const std::string& label) {
+ return pc_factory()->CreateAudioTrack(label, nullptr);
+}
+
+rtc::scoped_refptr<VideoTrackInterface> PeerConnectionWrapper::CreateVideoTrack(
+ const std::string& label) {
+ auto video_source = pc_factory()->CreateVideoSource(
+ rtc::MakeUnique<cricket::FakeVideoCapturer>());
+ return pc_factory()->CreateVideoTrack(label, video_source);
+}
+
rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddAudioTrack(
const std::string& track_label,
std::vector<MediaStreamInterface*> streams) {
- auto media_stream_track =
- pc_factory()->CreateAudioTrack(track_label, nullptr);
- return pc()->AddTrack(media_stream_track, std::move(streams));
+ return pc()->AddTrack(CreateAudioTrack(track_label), std::move(streams));
}
rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddVideoTrack(
const std::string& track_label,
std::vector<MediaStreamInterface*> streams) {
- auto video_source = pc_factory()->CreateVideoSource(
- rtc::MakeUnique<cricket::FakeVideoCapturer>());
- auto media_stream_track =
- pc_factory()->CreateVideoTrack(track_label, video_source);
- return pc()->AddTrack(media_stream_track, std::move(streams));
+ return pc()->AddTrack(CreateVideoTrack(track_label), std::move(streams));
}
PeerConnectionInterface::SignalingState
diff --git a/pc/peerconnectionwrapper.h b/pc/peerconnectionwrapper.h
index 8918a71..e7d19ea 100644
--- a/pc/peerconnectionwrapper.h
+++ b/pc/peerconnectionwrapper.h
@@ -93,6 +93,28 @@
bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc,
RTCError* error_out);
+ // The following are wrappers for the underlying PeerConnection's
+ // AddTransceiver method. They return the result of calling AddTransceiver
+ // with the given arguments, DCHECKing if there is an error.
+ rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
+ cricket::MediaType media_type);
+ rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
+ cricket::MediaType media_type,
+ const RtpTransceiverInit& init);
+ rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track);
+ rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
+ rtc::scoped_refptr<MediaStreamTrackInterface> track,
+ const RtpTransceiverInit& init);
+
+ // Returns a new dummy audio track with the given label.
+ rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
+ const std::string& label);
+
+ // Returns a new dummy video track with the given label.
+ rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack(
+ const std::string& label);
+
// Calls the underlying PeerConnection's AddTrack method with an audio media
// stream track not bound to any source.
rtc::scoped_refptr<RtpSenderInterface> AddAudioTrack(
diff --git a/pc/rtpreceiver.cc b/pc/rtpreceiver.cc
index da7e642..4968ac1 100644
--- a/pc/rtpreceiver.cc
+++ b/pc/rtpreceiver.cc
@@ -22,16 +22,16 @@
namespace webrtc {
AudioRtpReceiver::AudioRtpReceiver(
- const std::string& track_id,
+ const std::string& receiver_id,
std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams,
uint32_t ssrc,
cricket::VoiceChannel* channel)
- : id_(track_id),
+ : id_(receiver_id),
ssrc_(ssrc),
channel_(channel),
track_(AudioTrackProxy::Create(
rtc::Thread::Current(),
- AudioTrack::Create(track_id,
+ AudioTrack::Create(receiver_id,
RemoteAudioSource::Create(ssrc, channel)))),
streams_(std::move(streams)),
cached_track_enabled_(track_->enabled()) {
diff --git a/pc/rtpreceiver.h b/pc/rtpreceiver.h
index a1af13c..6df4642 100644
--- a/pc/rtpreceiver.h
+++ b/pc/rtpreceiver.h
@@ -50,11 +50,10 @@
// TODO(deadbeef): Use rtc::Optional, or have another constructor that
// doesn't take an SSRC, and make this one DCHECK(ssrc != 0).
AudioRtpReceiver(
- const std::string& track_id,
+ const std::string& receiver_id,
std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams,
uint32_t ssrc,
cricket::VoiceChannel* channel);
-
virtual ~AudioRtpReceiver();
// ObserverInterface implementation