blob: 35d9265e03896d96a75c4fe8628dd05b65f97f29 [file] [log] [blame]
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This file contains tests for `RtpTransceiver`.
#include "pc/rtp_transceiver.h"
#include <memory>
#include "absl/types/optional.h"
#include "api/rtp_parameters.h"
#include "media/base/fake_media_engine.h"
#include "pc/test/mock_channel_interface.h"
#include "pc/test/mock_rtp_receiver_internal.h"
#include "pc/test/mock_rtp_sender_internal.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Optional;
using ::testing::Property;
using ::testing::Return;
using ::testing::ReturnRef;
namespace webrtc {
// Checks that a channel cannot be set on a stopped `RtpTransceiver`.
TEST(RtpTransceiverTest, CannotSetChannelOnStoppedTransceiver) {
auto cm = cricket::ChannelManager::Create(
nullptr, true, rtc::Thread::Current(), rtc::Thread::Current());
RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_AUDIO, cm.get());
cricket::MockChannelInterface channel1;
EXPECT_CALL(channel1, media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
EXPECT_CALL(channel1, SetFirstPacketReceivedCallback(_));
transceiver.SetChannel(&channel1);
EXPECT_EQ(&channel1, transceiver.channel());
// Stop the transceiver.
transceiver.StopInternal();
EXPECT_EQ(&channel1, transceiver.channel());
cricket::MockChannelInterface channel2;
EXPECT_CALL(channel2, media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
// Channel can no longer be set, so this call should be a no-op.
transceiver.SetChannel(&channel2);
EXPECT_EQ(&channel1, transceiver.channel());
}
// Checks that a channel can be unset on a stopped `RtpTransceiver`
TEST(RtpTransceiverTest, CanUnsetChannelOnStoppedTransceiver) {
auto cm = cricket::ChannelManager::Create(
nullptr, true, rtc::Thread::Current(), rtc::Thread::Current());
RtpTransceiver transceiver(cricket::MediaType::MEDIA_TYPE_VIDEO, cm.get());
cricket::MockChannelInterface channel;
EXPECT_CALL(channel, media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_VIDEO));
EXPECT_CALL(channel, SetFirstPacketReceivedCallback(_))
.WillRepeatedly(testing::Return());
transceiver.SetChannel(&channel);
EXPECT_EQ(&channel, transceiver.channel());
// Stop the transceiver.
transceiver.StopInternal();
EXPECT_EQ(&channel, transceiver.channel());
// Set the channel to `nullptr`.
transceiver.SetChannel(nullptr);
EXPECT_EQ(nullptr, transceiver.channel());
}
class RtpTransceiverUnifiedPlanTest : public ::testing::Test {
public:
RtpTransceiverUnifiedPlanTest()
: channel_manager_(cricket::ChannelManager::Create(
std::make_unique<cricket::FakeMediaEngine>(),
false,
rtc::Thread::Current(),
rtc::Thread::Current())),
transceiver_(RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
rtc::Thread::Current(),
sender_),
RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
rtc::Thread::Current(),
rtc::Thread::Current(),
receiver_),
channel_manager_.get(),
channel_manager_->GetSupportedAudioRtpHeaderExtensions(),
/* on_negotiation_needed= */ [] {}) {}
static rtc::scoped_refptr<MockRtpReceiverInternal> MockReceiver() {
auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
EXPECT_CALL(*receiver.get(), media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
return receiver;
}
static rtc::scoped_refptr<MockRtpSenderInternal> MockSender() {
auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
EXPECT_CALL(*sender.get(), media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
return sender;
}
rtc::scoped_refptr<MockRtpReceiverInternal> receiver_ = MockReceiver();
rtc::scoped_refptr<MockRtpSenderInternal> sender_ = MockSender();
std::unique_ptr<cricket::ChannelManager> channel_manager_;
RtpTransceiver transceiver_;
};
// Basic tests for Stop()
TEST_F(RtpTransceiverUnifiedPlanTest, StopSetsDirection) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
EXPECT_EQ(RtpTransceiverDirection::kInactive, transceiver_.direction());
EXPECT_FALSE(transceiver_.current_direction());
transceiver_.StopStandard();
EXPECT_EQ(RtpTransceiverDirection::kStopped, transceiver_.direction());
EXPECT_FALSE(transceiver_.current_direction());
transceiver_.StopTransceiverProcedure();
EXPECT_TRUE(transceiver_.current_direction());
EXPECT_EQ(RtpTransceiverDirection::kStopped, transceiver_.direction());
EXPECT_EQ(RtpTransceiverDirection::kStopped,
*transceiver_.current_direction());
}
class RtpTransceiverTestForHeaderExtensions : public ::testing::Test {
public:
RtpTransceiverTestForHeaderExtensions()
: channel_manager_(cricket::ChannelManager::Create(
std::make_unique<cricket::FakeMediaEngine>(),
false,
rtc::Thread::Current(),
rtc::Thread::Current())),
extensions_(
{RtpHeaderExtensionCapability("uri1",
1,
RtpTransceiverDirection::kSendOnly),
RtpHeaderExtensionCapability("uri2",
2,
RtpTransceiverDirection::kRecvOnly),
RtpHeaderExtensionCapability(RtpExtension::kMidUri,
3,
RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability(RtpExtension::kVideoRotationUri,
4,
RtpTransceiverDirection::kSendRecv)}),
transceiver_(RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
rtc::Thread::Current(),
sender_),
RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
rtc::Thread::Current(),
rtc::Thread::Current(),
receiver_),
channel_manager_.get(),
extensions_,
/* on_negotiation_needed= */ [] {}) {}
static rtc::scoped_refptr<MockRtpReceiverInternal> MockReceiver() {
auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
EXPECT_CALL(*receiver.get(), media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
return receiver;
}
static rtc::scoped_refptr<MockRtpSenderInternal> MockSender() {
auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
EXPECT_CALL(*sender.get(), media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
return sender;
}
rtc::scoped_refptr<MockRtpReceiverInternal> receiver_ = MockReceiver();
rtc::scoped_refptr<MockRtpSenderInternal> sender_ = MockSender();
std::unique_ptr<cricket::ChannelManager> channel_manager_;
std::vector<RtpHeaderExtensionCapability> extensions_;
RtpTransceiver transceiver_;
};
TEST_F(RtpTransceiverTestForHeaderExtensions, OffersChannelManagerList) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), extensions_);
}
TEST_F(RtpTransceiverTestForHeaderExtensions, ModifiesDirection) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
auto modified_extensions = extensions_;
modified_extensions[0].direction = RtpTransceiverDirection::kSendOnly;
EXPECT_TRUE(
transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions).ok());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), modified_extensions);
modified_extensions[0].direction = RtpTransceiverDirection::kRecvOnly;
EXPECT_TRUE(
transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions).ok());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), modified_extensions);
modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv;
EXPECT_TRUE(
transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions).ok());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), modified_extensions);
modified_extensions[0].direction = RtpTransceiverDirection::kInactive;
EXPECT_TRUE(
transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions).ok());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), modified_extensions);
}
TEST_F(RtpTransceiverTestForHeaderExtensions, AcceptsStoppedExtension) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
auto modified_extensions = extensions_;
modified_extensions[0].direction = RtpTransceiverDirection::kStopped;
EXPECT_TRUE(
transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions).ok());
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), modified_extensions);
}
TEST_F(RtpTransceiverTestForHeaderExtensions, RejectsUnsupportedExtension) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
std::vector<RtpHeaderExtensionCapability> modified_extensions(
{RtpHeaderExtensionCapability("uri3", 1,
RtpTransceiverDirection::kSendRecv)});
EXPECT_THAT(transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions),
Property(&RTCError::type, RTCErrorType::UNSUPPORTED_PARAMETER));
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), extensions_);
}
TEST_F(RtpTransceiverTestForHeaderExtensions,
RejectsStoppedMandatoryExtensions) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
std::vector<RtpHeaderExtensionCapability> modified_extensions = extensions_;
// Attempting to stop the mandatory MID extension.
modified_extensions[2].direction = RtpTransceiverDirection::kStopped;
EXPECT_THAT(transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions),
Property(&RTCError::type, RTCErrorType::INVALID_MODIFICATION));
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), extensions_);
modified_extensions = extensions_;
// Attempting to stop the mandatory video orientation extension.
modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
EXPECT_THAT(transceiver_.SetOfferedRtpHeaderExtensions(modified_extensions),
Property(&RTCError::type, RTCErrorType::INVALID_MODIFICATION));
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), extensions_);
}
TEST_F(RtpTransceiverTestForHeaderExtensions,
NoNegotiatedHdrExtsWithoutChannel) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(), ElementsAre());
}
TEST_F(RtpTransceiverTestForHeaderExtensions,
NoNegotiatedHdrExtsWithChannelWithoutNegotiation) {
EXPECT_CALL(*receiver_.get(), SetMediaChannel(_));
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetMediaChannel(_));
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
cricket::MockChannelInterface mock_channel;
EXPECT_CALL(mock_channel, SetFirstPacketReceivedCallback(_));
EXPECT_CALL(mock_channel, media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
EXPECT_CALL(mock_channel, media_channel()).WillRepeatedly(Return(nullptr));
transceiver_.SetChannel(&mock_channel);
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(), ElementsAre());
}
TEST_F(RtpTransceiverTestForHeaderExtensions, ReturnsNegotiatedHdrExts) {
EXPECT_CALL(*receiver_.get(), SetMediaChannel(_));
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetMediaChannel(_));
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
cricket::MockChannelInterface mock_channel;
EXPECT_CALL(mock_channel, SetFirstPacketReceivedCallback(_));
EXPECT_CALL(mock_channel, media_type())
.WillRepeatedly(Return(cricket::MediaType::MEDIA_TYPE_AUDIO));
EXPECT_CALL(mock_channel, media_channel()).WillRepeatedly(Return(nullptr));
cricket::RtpHeaderExtensions extensions = {webrtc::RtpExtension("uri1", 1),
webrtc::RtpExtension("uri2", 2)};
cricket::AudioContentDescription description;
description.set_rtp_header_extensions(extensions);
transceiver_.OnNegotiationUpdate(SdpType::kAnswer, &description);
transceiver_.SetChannel(&mock_channel);
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(),
ElementsAre(RtpHeaderExtensionCapability(
"uri1", 1, RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability(
"uri2", 2, RtpTransceiverDirection::kSendRecv)));
}
TEST_F(RtpTransceiverTestForHeaderExtensions,
ReturnsNegotiatedHdrExtsSecondTime) {
EXPECT_CALL(*receiver_.get(), StopAndEndTrack());
EXPECT_CALL(*sender_.get(), SetTransceiverAsStopped());
EXPECT_CALL(*sender_.get(), Stop());
cricket::RtpHeaderExtensions extensions = {webrtc::RtpExtension("uri1", 1),
webrtc::RtpExtension("uri2", 2)};
cricket::AudioContentDescription description;
description.set_rtp_header_extensions(extensions);
transceiver_.OnNegotiationUpdate(SdpType::kAnswer, &description);
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(),
ElementsAre(RtpHeaderExtensionCapability(
"uri1", 1, RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability(
"uri2", 2, RtpTransceiverDirection::kSendRecv)));
extensions = {webrtc::RtpExtension("uri3", 4),
webrtc::RtpExtension("uri5", 6)};
description.set_rtp_header_extensions(extensions);
transceiver_.OnNegotiationUpdate(SdpType::kAnswer, &description);
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(),
ElementsAre(RtpHeaderExtensionCapability(
"uri3", 4, RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability(
"uri5", 6, RtpTransceiverDirection::kSendRecv)));
}
} // namespace webrtc