blob: af6cbee3e9672ed733dcfff036c426397e831ee2 [file] [log] [blame]
/*
* Copyright (c) 2017 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.
*/
#include "call/rtp_demuxer.h"
#include <memory>
#include <set>
#include <string>
#include "call/ssrc_binding_observer.h"
#include "call/test/mock_rtp_packet_sink_interface.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/ptr_util.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AtMost;
using ::testing::InSequence;
using ::testing::NiceMock;
class MockSsrcBindingObserver : public SsrcBindingObserver {
public:
MOCK_METHOD2(OnSsrcBoundToRsid, void(const std::string& rsid, uint32_t ssrc));
MOCK_METHOD2(OnSsrcBoundToMid, void(const std::string& mid, uint32_t ssrc));
MOCK_METHOD3(OnSsrcBoundToMidRsid,
void(const std::string& mid,
const std::string& rsid,
uint32_t ssrc));
MOCK_METHOD2(OnSsrcBoundToPayloadType,
void(uint8_t payload_type, uint32_t ssrc));
};
class RtpDemuxerTest : public testing::Test {
protected:
~RtpDemuxerTest() {
for (auto* sink : sinks_to_tear_down_) {
demuxer_.RemoveSink(sink);
}
for (auto* observer : observers_to_tear_down_) {
demuxer_.DeregisterSsrcBindingObserver(observer);
}
}
// These are convenience methods for calling demuxer.AddSink with different
// parameters and will ensure that the sink is automatically removed when the
// test case finishes.
bool AddSink(const RtpDemuxerCriteria& criteria,
RtpPacketSinkInterface* sink) {
bool added = demuxer_.AddSink(criteria, sink);
if (added) {
sinks_to_tear_down_.insert(sink);
}
return added;
}
bool AddSinkOnlySsrc(uint32_t ssrc, RtpPacketSinkInterface* sink) {
RtpDemuxerCriteria criteria;
criteria.ssrcs = {ssrc};
return AddSink(criteria, sink);
}
bool AddSinkOnlyRsid(const std::string& rsid, RtpPacketSinkInterface* sink) {
RtpDemuxerCriteria criteria;
criteria.rsid = rsid;
return AddSink(criteria, sink);
}
bool AddSinkOnlyMid(const std::string& mid, RtpPacketSinkInterface* sink) {
RtpDemuxerCriteria criteria;
criteria.mid = mid;
return AddSink(criteria, sink);
}
bool AddSinkBothMidRsid(const std::string& mid,
const std::string& rsid,
RtpPacketSinkInterface* sink) {
RtpDemuxerCriteria criteria;
criteria.mid = mid;
criteria.rsid = rsid;
return AddSink(criteria, sink);
}
bool RemoveSink(RtpPacketSinkInterface* sink) {
sinks_to_tear_down_.erase(sink);
return demuxer_.RemoveSink(sink);
}
// These are convenience methods for calling
// demuxer.{Register|Unregister}SsrcBindingObserver such that observers are
// automatically removed when the test finishes.
void RegisterSsrcBindingObserver(SsrcBindingObserver* observer) {
demuxer_.RegisterSsrcBindingObserver(observer);
observers_to_tear_down_.insert(observer);
}
void DeregisterSsrcBindingObserver(SsrcBindingObserver* observer) {
demuxer_.DeregisterSsrcBindingObserver(observer);
observers_to_tear_down_.erase(observer);
}
// The CreatePacket* methods are helpers for creating new RTP packets with
// various attributes set. Tests should use the helper that provides the
// minimum information needed to exercise the behavior under test. Tests also
// should not rely on any behavior which is not clearly described in the
// helper name/arguments. Any additional settings that are not covered by the
// helper should be set manually on the packet once it has been returned.
// For example, most tests in this file do not care about the RTP sequence
// number, but to ensure that the returned packets are valid the helpers will
// auto-increment the sequence number starting with 1. Tests that rely on
// specific sequence number behavior should call SetSequenceNumber manually on
// the returned packet.
// Intended for use only by other CreatePacket* helpers.
std::unique_ptr<RtpPacketReceived> CreatePacket(
uint32_t ssrc,
RtpPacketReceived::ExtensionManager* extension_manager) {
auto packet = rtc::MakeUnique<RtpPacketReceived>(extension_manager);
packet->SetSsrc(ssrc);
packet->SetSequenceNumber(next_sequence_number_++);
return packet;
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrc(uint32_t ssrc) {
return CreatePacket(ssrc, nullptr);
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrcMid(
uint32_t ssrc,
const std::string& mid) {
RtpPacketReceived::ExtensionManager extension_manager;
extension_manager.Register<RtpMid>(11);
auto packet = CreatePacket(ssrc, &extension_manager);
packet->SetExtension<RtpMid>(mid);
return packet;
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrcRsid(
uint32_t ssrc,
const std::string& rsid) {
RtpPacketReceived::ExtensionManager extension_manager;
extension_manager.Register<RtpStreamId>(6);
auto packet = CreatePacket(ssrc, &extension_manager);
packet->SetExtension<RtpStreamId>(rsid);
return packet;
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrcRrid(
uint32_t ssrc,
const std::string& rrid) {
RtpPacketReceived::ExtensionManager extension_manager;
extension_manager.Register<RepairedRtpStreamId>(7);
auto packet = CreatePacket(ssrc, &extension_manager);
packet->SetExtension<RepairedRtpStreamId>(rrid);
return packet;
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrcMidRsid(
uint32_t ssrc,
const std::string& mid,
const std::string& rsid) {
RtpPacketReceived::ExtensionManager extension_manager;
extension_manager.Register<RtpMid>(11);
extension_manager.Register<RtpStreamId>(6);
auto packet = CreatePacket(ssrc, &extension_manager);
packet->SetExtension<RtpMid>(mid);
packet->SetExtension<RtpStreamId>(rsid);
return packet;
}
std::unique_ptr<RtpPacketReceived> CreatePacketWithSsrcRsidRrid(
uint32_t ssrc,
const std::string& rsid,
const std::string& rrid) {
RtpPacketReceived::ExtensionManager extension_manager;
extension_manager.Register<RtpStreamId>(6);
extension_manager.Register<RepairedRtpStreamId>(7);
auto packet = CreatePacket(ssrc, &extension_manager);
packet->SetExtension<RtpStreamId>(rsid);
packet->SetExtension<RepairedRtpStreamId>(rrid);
return packet;
}
RtpDemuxer demuxer_;
std::set<RtpPacketSinkInterface*> sinks_to_tear_down_;
std::set<SsrcBindingObserver*> observers_to_tear_down_;
uint16_t next_sequence_number_ = 1;
};
MATCHER_P(SamePacketAs, other, "") {
return arg.Ssrc() == other.Ssrc() &&
arg.SequenceNumber() == other.SequenceNumber();
}
TEST_F(RtpDemuxerTest, CanAddSinkBySsrc) {
MockRtpPacketSink sink;
constexpr uint32_t ssrc = 1;
EXPECT_TRUE(AddSinkOnlySsrc(ssrc, &sink));
}
TEST_F(RtpDemuxerTest, AllowAddSinkWithOverlappingPayloadTypesIfDifferentMid) {
const std::string mid1 = "v";
const std::string mid2 = "a";
constexpr uint8_t pt1 = 30;
constexpr uint8_t pt2 = 31;
constexpr uint8_t pt3 = 32;
RtpDemuxerCriteria pt1_pt2;
pt1_pt2.mid = mid1;
pt1_pt2.payload_types = {pt1, pt2};
MockRtpPacketSink sink1;
AddSink(pt1_pt2, &sink1);
RtpDemuxerCriteria pt1_pt3;
pt1_pt2.mid = mid2;
pt1_pt3.payload_types = {pt1, pt3};
MockRtpPacketSink sink2;
EXPECT_TRUE(AddSink(pt1_pt3, &sink2));
}
TEST_F(RtpDemuxerTest, RejectAddSinkForSameMidOnly) {
const std::string mid = "mid";
MockRtpPacketSink sink;
AddSinkOnlyMid(mid, &sink);
EXPECT_FALSE(AddSinkOnlyMid(mid, &sink));
}
TEST_F(RtpDemuxerTest, RejectAddSinkForSameMidRsid) {
const std::string mid = "v";
const std::string rsid = "1";
MockRtpPacketSink sink1;
AddSinkBothMidRsid(mid, rsid, &sink1);
MockRtpPacketSink sink2;
EXPECT_FALSE(AddSinkBothMidRsid(mid, rsid, &sink2));
}
TEST_F(RtpDemuxerTest, RejectAddSinkForConflictingMidAndMidRsid) {
const std::string mid = "v";
const std::string rsid = "1";
MockRtpPacketSink mid_sink;
AddSinkOnlyMid(mid, &mid_sink);
// This sink would never get any packets routed to it because the above sink
// would receive them all.
MockRtpPacketSink mid_rsid_sink;
EXPECT_FALSE(AddSinkBothMidRsid(mid, rsid, &mid_rsid_sink));
}
TEST_F(RtpDemuxerTest, RejectAddSinkForConflictingMidRsidAndMid) {
const std::string mid = "v";
const std::string rsid = "";
MockRtpPacketSink mid_rsid_sink;
AddSinkBothMidRsid(mid, rsid, &mid_rsid_sink);
// This sink would shadow the above sink.
MockRtpPacketSink mid_sink;
EXPECT_FALSE(AddSinkOnlyMid(mid, &mid_sink));
}
TEST_F(RtpDemuxerTest, AddSinkFailsIfCalledForTwoSinksWithSameSsrc) {
MockRtpPacketSink sink_a;
MockRtpPacketSink sink_b;
constexpr uint32_t ssrc = 1;
ASSERT_TRUE(AddSinkOnlySsrc(ssrc, &sink_a));
EXPECT_FALSE(AddSinkOnlySsrc(ssrc, &sink_b));
}
TEST_F(RtpDemuxerTest, AddSinkFailsIfCalledTwiceEvenIfSameSinkWithSameSsrc) {
MockRtpPacketSink sink;
constexpr uint32_t ssrc = 1;
ASSERT_TRUE(AddSinkOnlySsrc(ssrc, &sink));
EXPECT_FALSE(AddSinkOnlySsrc(ssrc, &sink));
}
// TODO(steveanton): Currently fails because payload type validation is not
// complete in AddSink (see note in rtp_demuxer.cc).
TEST_F(RtpDemuxerTest, DISABLED_RejectAddSinkForSamePayloadTypes) {
constexpr uint8_t pt1 = 30;
constexpr uint8_t pt2 = 31;
RtpDemuxerCriteria pt1_pt2;
pt1_pt2.payload_types = {pt1, pt2};
MockRtpPacketSink sink1;
AddSink(pt1_pt2, &sink1);
RtpDemuxerCriteria pt2_pt1;
pt2_pt1.payload_types = {pt2, pt1};
MockRtpPacketSink sink2;
EXPECT_FALSE(AddSink(pt2_pt1, &sink2));
}
// Routing Tests
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkBySsrc) {
constexpr uint32_t ssrcs[] = {101, 202, 303};
MockRtpPacketSink sinks[arraysize(ssrcs)];
for (size_t i = 0; i < arraysize(ssrcs); i++) {
AddSinkOnlySsrc(ssrcs[i], &sinks[i]);
}
for (size_t i = 0; i < arraysize(ssrcs); i++) {
auto packet = CreatePacketWithSsrc(ssrcs[i]);
EXPECT_CALL(sinks[i], OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByRsid) {
const std::string rsids[] = {"a", "b", "c"};
MockRtpPacketSink sinks[arraysize(rsids)];
for (size_t i = 0; i < arraysize(rsids); i++) {
AddSinkOnlyRsid(rsids[i], &sinks[i]);
}
for (size_t i = 0; i < arraysize(rsids); i++) {
auto packet = CreatePacketWithSsrcRsid(rtc::checked_cast<uint32_t>(i),
rsids[i]);
EXPECT_CALL(sinks[i], OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByMid) {
const std::string mids[] = {"a", "v", "s"};
MockRtpPacketSink sinks[arraysize(mids)];
for (size_t i = 0; i < arraysize(mids); i++) {
AddSinkOnlyMid(mids[i], &sinks[i]);
}
for (size_t i = 0; i < arraysize(mids); i++) {
auto packet = CreatePacketWithSsrcMid(rtc::checked_cast<uint32_t>(i),
mids[i]);
EXPECT_CALL(sinks[i], OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByMidAndRsid) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto packet = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByRepairedRsid) {
const std::string rrid = "1";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink;
AddSinkOnlyRsid(rrid, &sink);
auto packet_with_rrid = CreatePacketWithSsrcRrid(ssrc, rrid);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_rrid))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_rrid));
}
TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByPayloadType) {
constexpr uint32_t ssrc = 10;
constexpr uint8_t payload_type = 30;
MockRtpPacketSink sink;
RtpDemuxerCriteria criteria;
criteria.payload_types = {payload_type};
AddSink(criteria, &sink);
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(payload_type);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, PacketsDeliveredInRightOrder) {
constexpr uint32_t ssrc = 101;
MockRtpPacketSink sink;
AddSinkOnlySsrc(ssrc, &sink);
std::unique_ptr<RtpPacketReceived> packets[5];
for (size_t i = 0; i < arraysize(packets); i++) {
packets[i] = CreatePacketWithSsrc(ssrc);
packets[i]->SetSequenceNumber(rtc::checked_cast<uint16_t>(i));
}
InSequence sequence;
for (const auto& packet : packets) {
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
}
for (const auto& packet : packets) {
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, SinkMappedToMultipleSsrcs) {
constexpr uint32_t ssrcs[] = {404, 505, 606};
MockRtpPacketSink sink;
for (uint32_t ssrc : ssrcs) {
AddSinkOnlySsrc(ssrc, &sink);
}
// The sink which is associated with multiple SSRCs gets the callback
// triggered for each of those SSRCs.
for (uint32_t ssrc : ssrcs) {
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, NoCallbackOnSsrcSinkRemovedBeforeFirstPacket) {
constexpr uint32_t ssrc = 404;
MockRtpPacketSink sink;
AddSinkOnlySsrc(ssrc, &sink);
ASSERT_TRUE(RemoveSink(&sink));
// The removed sink does not get callbacks.
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0); // Not called.
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, NoCallbackOnSsrcSinkRemovedAfterFirstPacket) {
constexpr uint32_t ssrc = 404;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlySsrc(ssrc, &sink);
InSequence sequence;
for (size_t i = 0; i < 10; i++) {
ASSERT_TRUE(demuxer_.OnRtpPacket(*CreatePacketWithSsrc(ssrc)));
}
ASSERT_TRUE(RemoveSink(&sink));
// The removed sink does not get callbacks.
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0); // Not called.
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
// An SSRC may only be mapped to a single sink. However, since configuration
// of this associations might come from the network, we need to fail gracefully.
TEST_F(RtpDemuxerTest, OnlyOneSinkPerSsrcGetsOnRtpPacketTriggered) {
MockRtpPacketSink sinks[3];
constexpr uint32_t ssrc = 404;
ASSERT_TRUE(AddSinkOnlySsrc(ssrc, &sinks[0]));
ASSERT_FALSE(AddSinkOnlySsrc(ssrc, &sinks[1]));
ASSERT_FALSE(AddSinkOnlySsrc(ssrc, &sinks[2]));
// The first sink associated with the SSRC remains active; other sinks
// were not really added, and so do not get OnRtpPacket() called.
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sinks[0], OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_CALL(sinks[1], OnRtpPacket(_)).Times(0);
EXPECT_CALL(sinks[2], OnRtpPacket(_)).Times(0);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, NoRepeatedCallbackOnRepeatedAddSinkForSameSink) {
constexpr uint32_t ssrc = 111;
MockRtpPacketSink sink;
ASSERT_TRUE(AddSinkOnlySsrc(ssrc, &sink));
ASSERT_FALSE(AddSinkOnlySsrc(ssrc, &sink));
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, RemoveSinkReturnsFalseForNeverAddedSink) {
MockRtpPacketSink sink;
EXPECT_FALSE(RemoveSink(&sink));
}
TEST_F(RtpDemuxerTest, RemoveSinkReturnsTrueForPreviouslyAddedSsrcSink) {
constexpr uint32_t ssrc = 101;
MockRtpPacketSink sink;
AddSinkOnlySsrc(ssrc, &sink);
EXPECT_TRUE(RemoveSink(&sink));
}
TEST_F(RtpDemuxerTest,
RemoveSinkReturnsTrueForUnresolvedPreviouslyAddedRsidSink) {
const std::string rsid = "a";
MockRtpPacketSink sink;
AddSinkOnlyRsid(rsid, &sink);
EXPECT_TRUE(RemoveSink(&sink));
}
TEST_F(RtpDemuxerTest,
RemoveSinkReturnsTrueForResolvedPreviouslyAddedRsidSink) {
const std::string rsid = "a";
constexpr uint32_t ssrc = 101;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyRsid(rsid, &sink);
ASSERT_TRUE(demuxer_.OnRtpPacket(*CreatePacketWithSsrcRsid(ssrc, rsid)));
EXPECT_TRUE(RemoveSink(&sink));
}
TEST_F(RtpDemuxerTest, RsidLearnedAndLaterPacketsDeliveredWithOnlySsrc) {
MockRtpPacketSink sink;
const std::string rsid = "a";
AddSinkOnlyRsid(rsid, &sink);
// Create a sequence of RTP packets, where only the first one actually
// mentions the RSID.
std::unique_ptr<RtpPacketReceived> packets[5];
constexpr uint32_t rsid_ssrc = 111;
packets[0] = CreatePacketWithSsrcRsid(rsid_ssrc, rsid);
for (size_t i = 1; i < arraysize(packets); i++) {
packets[i] = CreatePacketWithSsrc(rsid_ssrc);
}
// The first packet associates the RSID with the SSRC, thereby allowing the
// demuxer to correctly demux all of the packets.
InSequence sequence;
for (const auto& packet : packets) {
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
}
for (const auto& packet : packets) {
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
TEST_F(RtpDemuxerTest, NoCallbackOnRsidSinkRemovedBeforeFirstPacket) {
MockRtpPacketSink sink;
const std::string rsid = "a";
AddSinkOnlyRsid(rsid, &sink);
// Sink removed - it won't get triggers even if packets with its RSID arrive.
ASSERT_TRUE(RemoveSink(&sink));
constexpr uint32_t ssrc = 111;
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0); // Not called.
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, NoCallbackOnRsidSinkRemovedAfterFirstPacket) {
NiceMock<MockRtpPacketSink> sink;
const std::string rsid = "a";
AddSinkOnlyRsid(rsid, &sink);
InSequence sequence;
constexpr uint32_t ssrc = 111;
for (size_t i = 0; i < 10; i++) {
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// Sink removed - it won't get triggers even if packets with its RSID arrive.
ASSERT_TRUE(RemoveSink(&sink));
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0); // Not called.
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, NoCallbackOnMidSinkRemovedBeforeFirstPacket) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink;
AddSinkOnlyMid(mid, &sink);
RemoveSink(&sink);
auto packet = CreatePacketWithSsrcMid(ssrc, mid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, NoCallbackOnMidSinkRemovedAfterFirstPacket) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
auto p1 = CreatePacketWithSsrcMid(ssrc, mid);
demuxer_.OnRtpPacket(*p1);
RemoveSink(&sink);
auto p2 = CreatePacketWithSsrcMid(ssrc, mid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*p2));
}
TEST_F(RtpDemuxerTest, NoCallbackOnMidRsidSinkRemovedAfterFirstPacket) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto p1 = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
demuxer_.OnRtpPacket(*p1);
RemoveSink(&sink);
auto p2 = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*p2));
}
// The RSID to SSRC mapping should be one-to-one. If we end up receiving
// two (or more) packets with the same SSRC, but different RSIDs, we guarantee
// delivery to one of them but not both.
TEST_F(RtpDemuxerTest, FirstSsrcAssociatedWithAnRsidIsNotForgotten) {
// Each sink has a distinct RSID.
MockRtpPacketSink sink_a;
const std::string rsid_a = "a";
AddSinkOnlyRsid(rsid_a, &sink_a);
MockRtpPacketSink sink_b;
const std::string rsid_b = "b";
AddSinkOnlyRsid(rsid_b, &sink_b);
InSequence sequence; // Verify that the order of delivery is unchanged.
constexpr uint32_t shared_ssrc = 100;
// First a packet with |rsid_a| is received, and |sink_a| is associated with
// its SSRC.
auto packet_a = CreatePacketWithSsrcRsid(shared_ssrc, rsid_a);
EXPECT_CALL(sink_a, OnRtpPacket(SamePacketAs(*packet_a))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_a));
// Second, a packet with |rsid_b| is received. We guarantee that |sink_b|
// receives it.
auto packet_b = CreatePacketWithSsrcRsid(shared_ssrc, rsid_b);
EXPECT_CALL(sink_a, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink_b, OnRtpPacket(SamePacketAs(*packet_b))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_b));
// Known edge-case; adding a new RSID association makes us re-examine all
// SSRCs. |sink_b| may or may not be associated with the SSRC now; we make
// no promises on that. However, since the RSID is specified and it cannot be
// found the packet should be dropped.
MockRtpPacketSink sink_c;
const std::string rsid_c = "c";
constexpr uint32_t some_other_ssrc = shared_ssrc + 1;
AddSinkOnlySsrc(some_other_ssrc, &sink_c);
auto packet_c = CreatePacketWithSsrcMid(shared_ssrc, rsid_c);
EXPECT_CALL(sink_a, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink_b, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink_c, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet_c));
}
TEST_F(RtpDemuxerTest, MultipleRsidsOnSameSink) {
MockRtpPacketSink sink;
const std::string rsids[] = {"a", "b", "c"};
for (const std::string& rsid : rsids) {
AddSinkOnlyRsid(rsid, &sink);
}
InSequence sequence;
for (size_t i = 0; i < arraysize(rsids); i++) {
// Assign different SSRCs and sequence numbers to all packets.
const uint32_t ssrc = 1000 + static_cast<uint32_t>(i);
const uint16_t sequence_number = 50 + static_cast<uint16_t>(i);
auto packet = CreatePacketWithSsrcRsid(ssrc, rsids[i]);
packet->SetSequenceNumber(sequence_number);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
// RSIDs are given higher priority than SSRC because we believe senders are less
// likely to mislabel packets with RSID than mislabel them with SSRCs.
TEST_F(RtpDemuxerTest, SinkWithBothRsidAndSsrcAssociations) {
MockRtpPacketSink sink;
constexpr uint32_t standalone_ssrc = 10101;
constexpr uint32_t rsid_ssrc = 20202;
const std::string rsid = "1";
AddSinkOnlySsrc(standalone_ssrc, &sink);
AddSinkOnlyRsid(rsid, &sink);
InSequence sequence;
auto ssrc_packet = CreatePacketWithSsrc(standalone_ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*ssrc_packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*ssrc_packet));
auto rsid_packet = CreatePacketWithSsrcRsid(rsid_ssrc, rsid);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*rsid_packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*rsid_packet));
}
// Packets are always guaranteed to be routed to only one sink.
TEST_F(RtpDemuxerTest, AssociatingByRsidAndBySsrcCannotTriggerDoubleCall) {
constexpr uint32_t ssrc = 10101;
const std::string rsid = "a";
MockRtpPacketSink sink;
AddSinkOnlySsrc(ssrc, &sink);
AddSinkOnlyRsid(rsid, &sink);
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundToMid) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
auto packet = CreatePacketWithSsrcMid(ssrc, mid);
EXPECT_CALL(observer, OnSsrcBoundToMid(mid, ssrc));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundToRsid) {
const std::string rsid = "1";
constexpr uint32_t ssrc = 111;
// Only RSIDs which the demuxer knows may be resolved.
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyRsid(rsid, &sink);
NiceMock<MockSsrcBindingObserver> rsid_resolution_observers[3];
for (auto& observer : rsid_resolution_observers) {
RegisterSsrcBindingObserver(&observer);
EXPECT_CALL(observer, OnSsrcBoundToRsid(rsid, ssrc)).Times(1);
}
// The expected calls to OnSsrcBoundToRsid() will be triggered by this.
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundToMidRsid) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkBothMidRsid(mid, rsid, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
auto packet = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
EXPECT_CALL(observer, OnSsrcBoundToMidRsid(mid, rsid, ssrc));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundToPayloadType) {
constexpr uint8_t payload_type = 3;
constexpr uint32_t ssrc = 10;
RtpDemuxerCriteria criteria;
criteria.payload_types = {payload_type};
NiceMock<MockRtpPacketSink> sink;
AddSink(criteria, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(payload_type);
EXPECT_CALL(observer, OnSsrcBoundToPayloadType(payload_type, ssrc));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// If one sink is associated with SSRC x, and another sink with RSID y, then if
// we receive a packet with both SSRC x and RSID y, route that to only the sink
// for RSID y since we believe RSID tags to be more trustworthy than signaled
// SSRCs.
TEST_F(RtpDemuxerTest,
PacketFittingBothRsidSinkAndSsrcSinkGivenOnlyToRsidSink) {
constexpr uint32_t ssrc = 111;
MockRtpPacketSink ssrc_sink;
AddSinkOnlySsrc(ssrc, &ssrc_sink);
const std::string rsid = "a";
MockRtpPacketSink rsid_sink;
AddSinkOnlyRsid(rsid, &rsid_sink);
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(ssrc_sink, OnRtpPacket(_)).Times(0);
EXPECT_CALL(rsid_sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// We're not expecting RSIDs to be resolved to SSRCs which were previously
// mapped to sinks, and make no guarantees except for graceful handling.
TEST_F(RtpDemuxerTest,
GracefullyHandleRsidBeingMappedToPrevouslyAssociatedSsrc) {
constexpr uint32_t ssrc = 111;
NiceMock<MockRtpPacketSink> ssrc_sink;
AddSinkOnlySsrc(ssrc, &ssrc_sink);
const std::string rsid = "a";
NiceMock<MockRtpPacketSink> rsid_sink;
AddSinkOnlyRsid(rsid, &rsid_sink);
NiceMock<MockSsrcBindingObserver> observer;
RegisterSsrcBindingObserver(&observer);
// The SSRC was mapped to an SSRC sink, but was even active (packets flowed
// over it).
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
demuxer_.OnRtpPacket(*packet);
// If the SSRC sink is ever removed, the RSID sink *might* receive indications
// of packets, and observers *might* be informed. Only graceful handling
// is guaranteed.
RemoveSink(&ssrc_sink);
EXPECT_CALL(rsid_sink, OnRtpPacket(SamePacketAs(*packet))).Times(AtLeast(0));
EXPECT_CALL(observer, OnSsrcBoundToRsid(rsid, ssrc)).Times(AtLeast(0));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// Tests that when one MID sink is configured, packets that include the MID
// extension will get routed to that sink and any packets that use the same
// SSRC as one of those packets later will also get routed to the sink, even
// if a new SSRC is introduced for the same MID.
TEST_F(RtpDemuxerTest, RoutedByMidWhenSsrcAdded) {
const std::string mid = "v";
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
constexpr uint32_t ssrc1 = 10;
constexpr uint32_t ssrc2 = 11;
auto packet_ssrc1_mid = CreatePacketWithSsrcMid(ssrc1, mid);
demuxer_.OnRtpPacket(*packet_ssrc1_mid);
auto packet_ssrc2_mid = CreatePacketWithSsrcMid(ssrc2, mid);
demuxer_.OnRtpPacket(*packet_ssrc2_mid);
auto packet_ssrc1_only = CreatePacketWithSsrc(ssrc1);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_ssrc1_only))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_ssrc1_only));
auto packet_ssrc2_only = CreatePacketWithSsrc(ssrc2);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_ssrc2_only))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_ssrc2_only));
}
TEST_F(RtpDemuxerTest, DontLearnMidSsrcBindingBeforeSinkAdded) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
auto packet_ssrc_mid = CreatePacketWithSsrcMid(ssrc, mid);
ASSERT_FALSE(demuxer_.OnRtpPacket(*packet_ssrc_mid));
MockRtpPacketSink sink;
AddSinkOnlyMid(mid, &sink);
auto packet_ssrc_only = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet_ssrc_only));
}
TEST_F(RtpDemuxerTest, DontForgetMidSsrcBindingWhenSinkRemoved) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink1;
AddSinkOnlyMid(mid, &sink1);
auto packet_with_mid = CreatePacketWithSsrcMid(ssrc, mid);
demuxer_.OnRtpPacket(*packet_with_mid);
RemoveSink(&sink1);
MockRtpPacketSink sink2;
AddSinkOnlyMid(mid, &sink2);
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink2, OnRtpPacket(SamePacketAs(*packet_with_ssrc)));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
// If a sink is added with only a MID, then any packet with that MID no matter
// the RSID should be routed to that sink.
TEST_F(RtpDemuxerTest, RoutedByMidWithAnyRsid) {
const std::string mid = "v";
const std::string rsid1 = "1";
const std::string rsid2 = "2";
constexpr uint32_t ssrc1 = 10;
constexpr uint32_t ssrc2 = 11;
MockRtpPacketSink sink;
AddSinkOnlyMid(mid, &sink);
InSequence sequence;
auto packet_ssrc1_rsid1 = CreatePacketWithSsrcMidRsid(ssrc1, mid, rsid1);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_ssrc1_rsid1))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_ssrc1_rsid1));
auto packet_ssrc2_rsid2 = CreatePacketWithSsrcMidRsid(ssrc2, mid, rsid2);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_ssrc2_rsid2))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_ssrc2_rsid2));
}
// These two tests verify that for a sink added with a MID, RSID pair, if the
// MID and RSID are learned in separate packets (e.g., because the header
// extensions are sent separately), then a later packet with just SSRC will get
// routed to that sink.
// The first test checks that the functionality works when MID is learned first.
// The second test checks that the functionality works when RSID is learned
// first.
TEST_F(RtpDemuxerTest, LearnMidThenRsidSeparatelyAndRouteBySsrc) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto packet_with_mid = CreatePacketWithSsrcMid(ssrc, mid);
ASSERT_FALSE(demuxer_.OnRtpPacket(*packet_with_mid));
auto packet_with_rsid = CreatePacketWithSsrcRsid(ssrc, rsid);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet_with_rsid));
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_ssrc))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
TEST_F(RtpDemuxerTest, LearnRsidThenMidSeparatelyAndRouteBySsrc) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto packet_with_rsid = CreatePacketWithSsrcRsid(ssrc, rsid);
ASSERT_FALSE(demuxer_.OnRtpPacket(*packet_with_rsid));
auto packet_with_mid = CreatePacketWithSsrcMid(ssrc, mid);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet_with_mid));
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_ssrc))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
TEST_F(RtpDemuxerTest, DontLearnMidRsidBindingBeforeSinkAdded) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
auto packet_with_both = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
ASSERT_FALSE(demuxer_.OnRtpPacket(*packet_with_both));
MockRtpPacketSink sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
TEST_F(RtpDemuxerTest, DontForgetMidRsidBindingWhenSinkRemoved) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink1;
AddSinkBothMidRsid(mid, rsid, &sink1);
auto packet_with_both = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
demuxer_.OnRtpPacket(*packet_with_both);
RemoveSink(&sink1);
MockRtpPacketSink sink2;
AddSinkBothMidRsid(mid, rsid, &sink2);
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink2, OnRtpPacket(SamePacketAs(*packet_with_ssrc)));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
TEST_F(RtpDemuxerTest, LearnMidRsidBindingAfterSinkAdded) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkBothMidRsid(mid, rsid, &sink);
auto packet_with_both = CreatePacketWithSsrcMidRsid(ssrc, mid, rsid);
demuxer_.OnRtpPacket(*packet_with_both);
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_ssrc)));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
TEST_F(RtpDemuxerTest, DropByPayloadTypeIfNoSink) {
constexpr uint8_t payload_type = 30;
constexpr uint32_t ssrc = 10;
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(payload_type);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
// For legacy applications, it's possible for us to demux if the payload type is
// unique. But if multiple sinks are registered with different MIDs and the same
// payload types, then we cannot route a packet with just payload type because
// it is ambiguous which sink it should be sent to.
TEST_F(RtpDemuxerTest, DropByPayloadTypeIfAddedInMultipleSinks) {
const std::string mid1 = "v";
const std::string mid2 = "a";
constexpr uint8_t payload_type = 30;
constexpr uint32_t ssrc = 10;
RtpDemuxerCriteria mid1_pt;
mid1_pt.mid = mid1;
mid1_pt.payload_types = {payload_type};
MockRtpPacketSink sink1;
AddSink(mid1_pt, &sink1);
RtpDemuxerCriteria mid2_pt;
mid2_pt.mid = mid2;
mid2_pt.payload_types = {payload_type};
MockRtpPacketSink sink2;
AddSink(mid2_pt, &sink2);
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(payload_type);
EXPECT_CALL(sink1, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink2, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
// If two sinks are added with different MIDs but the same payload types, then
// we cannot demux on the payload type only unless one of the sinks is removed.
TEST_F(RtpDemuxerTest, RoutedByPayloadTypeIfAmbiguousSinkRemoved) {
const std::string mid1 = "v";
const std::string mid2 = "a";
constexpr uint8_t payload_type = 30;
constexpr uint32_t ssrc = 10;
RtpDemuxerCriteria mid1_pt;
mid1_pt.mid = mid1;
mid1_pt.payload_types = {payload_type};
MockRtpPacketSink sink1;
AddSink(mid1_pt, &sink1);
RtpDemuxerCriteria mid2_pt;
mid2_pt.mid = mid2;
mid2_pt.payload_types = {payload_type};
MockRtpPacketSink sink2;
AddSink(mid2_pt, &sink2);
RemoveSink(&sink1);
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(payload_type);
EXPECT_CALL(sink1, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink2, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, RoutedByPayloadTypeLatchesSsrc) {
constexpr uint8_t payload_type = 30;
constexpr uint32_t ssrc = 10;
RtpDemuxerCriteria pt;
pt.payload_types = {payload_type};
NiceMock<MockRtpPacketSink> sink;
AddSink(pt, &sink);
auto packet_with_pt = CreatePacketWithSsrc(ssrc);
packet_with_pt->SetPayloadType(payload_type);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet_with_pt));
auto packet_with_ssrc = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_ssrc))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_ssrc));
}
// RSIDs are scoped within MID, so if two sinks are registered with the same
// RSIDs but different MIDs, then packets containing both extensions should be
// routed to the correct one.
TEST_F(RtpDemuxerTest, PacketWithSameRsidDifferentMidRoutedToProperSink) {
const std::string mid1 = "mid1";
const std::string mid2 = "mid2";
const std::string rsid = "rsid";
constexpr uint32_t ssrc1 = 10;
constexpr uint32_t ssrc2 = 11;
NiceMock<MockRtpPacketSink> mid1_sink;
AddSinkBothMidRsid(mid1, rsid, &mid1_sink);
MockRtpPacketSink mid2_sink;
AddSinkBothMidRsid(mid2, rsid, &mid2_sink);
auto packet_mid1 = CreatePacketWithSsrcMidRsid(ssrc1, mid1, rsid);
ASSERT_TRUE(demuxer_.OnRtpPacket(*packet_mid1));
auto packet_mid2 = CreatePacketWithSsrcMidRsid(ssrc2, mid2, rsid);
EXPECT_CALL(mid2_sink, OnRtpPacket(SamePacketAs(*packet_mid2))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_mid2));
}
// If a sink is first bound to a given SSRC by signaling but later a new sink is
// bound to a given MID by a later signaling, then when a packet arrives with
// both the SSRC and MID, then the signaled MID sink should take precedence.
TEST_F(RtpDemuxerTest, SignaledMidShouldOverwriteSignaledSsrc) {
constexpr uint32_t ssrc = 11;
const std::string mid = "mid";
MockRtpPacketSink ssrc_sink;
AddSinkOnlySsrc(ssrc, &ssrc_sink);
MockRtpPacketSink mid_sink;
AddSinkOnlyMid(mid, &mid_sink);
auto p = CreatePacketWithSsrcMid(ssrc, mid);
EXPECT_CALL(ssrc_sink, OnRtpPacket(_)).Times(0);
EXPECT_CALL(mid_sink, OnRtpPacket(SamePacketAs(*p))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*p));
}
// Extends the previous test to also ensure that later packets that do not
// specify MID are still routed to the MID sink rather than the overwritten SSRC
// sink.
TEST_F(RtpDemuxerTest, SignaledMidShouldOverwriteSignalledSsrcPersistent) {
constexpr uint32_t ssrc = 11;
const std::string mid = "mid";
MockRtpPacketSink ssrc_sink;
AddSinkOnlySsrc(ssrc, &ssrc_sink);
NiceMock<MockRtpPacketSink> mid_sink;
AddSinkOnlyMid(mid, &mid_sink);
EXPECT_CALL(ssrc_sink, OnRtpPacket(_)).Times(0);
auto packet_with_mid = CreatePacketWithSsrcMid(ssrc, mid);
demuxer_.OnRtpPacket(*packet_with_mid);
auto packet_without_mid = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(mid_sink, OnRtpPacket(SamePacketAs(*packet_without_mid)))
.Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_without_mid));
}
TEST_F(RtpDemuxerTest, RouteByPayloadTypeMultipleMatch) {
constexpr uint32_t ssrc = 10;
constexpr uint8_t pt1 = 30;
constexpr uint8_t pt2 = 31;
MockRtpPacketSink sink;
RtpDemuxerCriteria criteria;
criteria.payload_types = {pt1, pt2};
AddSink(criteria, &sink);
auto packet_with_pt1 = CreatePacketWithSsrc(ssrc);
packet_with_pt1->SetPayloadType(pt1);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_pt1)));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_pt1));
auto packet_with_pt2 = CreatePacketWithSsrc(ssrc);
packet_with_pt2->SetPayloadType(pt2);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet_with_pt2)));
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_with_pt2));
}
TEST_F(RtpDemuxerTest, DontDemuxOnMidAloneIfAddedWithRsid) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink;
AddSinkBothMidRsid(mid, rsid, &sink);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
auto packet = CreatePacketWithSsrcMid(ssrc, mid);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
TEST_F(RtpDemuxerTest, DemuxBySsrcEvenWithMidAndRsid) {
const std::string mid = "v";
const std::string rsid = "1";
constexpr uint32_t ssrc = 10;
RtpDemuxerCriteria criteria;
criteria.rsid = rsid;
criteria.mid = mid;
criteria.ssrcs = {ssrc};
MockRtpPacketSink sink;
AddSink(criteria, &sink);
auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// In slight deviation from the BUNDLE spec, if we match a sink according to
// SSRC, then we do not verify payload type against the criteria and defer to
// the sink to check that it is correct.
TEST_F(RtpDemuxerTest, DoNotCheckPayloadTypeIfMatchedByOtherCriteria) {
constexpr uint32_t ssrc = 10;
constexpr uint8_t payload_type = 30;
constexpr uint8_t different_payload_type = payload_type + 1;
RtpDemuxerCriteria criteria;
criteria.ssrcs = {ssrc};
criteria.payload_types = {payload_type};
MockRtpPacketSink sink;
AddSink(criteria, &sink);
auto packet = CreatePacketWithSsrc(ssrc);
packet->SetPayloadType(different_payload_type);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// If a repair packet includes an RSID it should be ignored and the packet
// should be routed by its RRID.
TEST_F(RtpDemuxerTest, PacketWithRsidAndRridRoutedByRrid) {
const std::string rsid = "1";
const std::string rrid = "1r";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink_rsid;
AddSinkOnlyRsid(rsid, &sink_rsid);
MockRtpPacketSink sink_rrid;
AddSinkOnlyRsid(rrid, &sink_rrid);
auto packet = CreatePacketWithSsrcRsidRrid(ssrc, rsid, rrid);
EXPECT_CALL(sink_rsid, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink_rrid, OnRtpPacket(SamePacketAs(*packet))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
// Same test as above but checks that the latched SSRC routes to the RRID sink.
TEST_F(RtpDemuxerTest, PacketWithRsidAndRridLatchesSsrcToRrid) {
const std::string rsid = "1";
const std::string rrid = "1r";
constexpr uint32_t ssrc = 10;
MockRtpPacketSink sink_rsid;
AddSinkOnlyRsid(rsid, &sink_rsid);
NiceMock<MockRtpPacketSink> sink_rrid;
AddSinkOnlyRsid(rrid, &sink_rrid);
auto packet_rsid_rrid = CreatePacketWithSsrcRsidRrid(ssrc, rsid, rrid);
demuxer_.OnRtpPacket(*packet_rsid_rrid);
auto packet_ssrc_only = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink_rsid, OnRtpPacket(_)).Times(0);
EXPECT_CALL(sink_rrid, OnRtpPacket(SamePacketAs(*packet_ssrc_only))).Times(1);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet_ssrc_only));
}
// Tests that a packet which includes MID and RSID is dropped and not routed by
// SSRC if the MID and RSID do not match an added sink.
TEST_F(RtpDemuxerTest, PacketWithMidAndUnknownRsidIsNotRoutedBySsrc) {
constexpr uint32_t ssrc = 10;
const std::string mid = "v";
const std::string rsid = "1";
const std::string wrong_rsid = "2";
RtpDemuxerCriteria criteria;
criteria.mid = mid;
criteria.rsid = rsid;
criteria.ssrcs = {ssrc};
MockRtpPacketSink sink;
AddSink(criteria, &sink);
auto packet = CreatePacketWithSsrcMidRsid(ssrc, mid, wrong_rsid);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
// Tests that a packet which includes MID and RSID is dropped and not routed by
// payload type if the MID and RSID do not match an added sink.
TEST_F(RtpDemuxerTest, PacketWithMidAndUnknownRsidIsNotRoutedByPayloadType) {
constexpr uint32_t ssrc = 10;
const std::string mid = "v";
const std::string rsid = "1";
const std::string wrong_rsid = "2";
constexpr uint8_t payload_type = 30;
RtpDemuxerCriteria criteria;
criteria.mid = mid;
criteria.rsid = rsid;
criteria.payload_types = {payload_type};
MockRtpPacketSink sink;
AddSink(criteria, &sink);
auto packet = CreatePacketWithSsrcMidRsid(ssrc, mid, wrong_rsid);
packet->SetPayloadType(payload_type);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0);
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
// Observers are only notified of an SSRC binding to an RSID if we care about
// the RSID (i.e., have a sink added for that RSID).
TEST_F(RtpDemuxerTest, ObserversNotNotifiedOfUntrackedRsids) {
const std::string rsid = "1";
constexpr uint32_t ssrc = 111;
MockSsrcBindingObserver rsid_resolution_observers[3];
for (auto& observer : rsid_resolution_observers) {
RegisterSsrcBindingObserver(&observer);
EXPECT_CALL(observer, OnSsrcBoundToRsid(_, _)).Times(0);
}
// Since no sink is registered for this SSRC/RSID, expect the packet to not be
// routed and no observers notified of the SSRC -> RSID binding.
EXPECT_FALSE(demuxer_.OnRtpPacket(*CreatePacketWithSsrcRsid(ssrc, rsid)));
}
// Ensure that observers are notified of SSRC bindings only once per unique
// binding source (e.g., SSRC -> MID, SSRC -> RSID, etc.)
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundtoMidOnlyOnce) {
const std::string mid = "v";
constexpr uint32_t ssrc = 10;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
EXPECT_CALL(observer, OnSsrcBoundToMid(mid, ssrc)).Times(1);
demuxer_.OnRtpPacket(*CreatePacketWithSsrcMid(ssrc, mid));
demuxer_.OnRtpPacket(*CreatePacketWithSsrcMid(ssrc, mid));
}
// Ensure that when a new SSRC -> MID binding is discovered observers are also
// notified of that, even if there has already been an SSRC bound to the MID.
TEST_F(RtpDemuxerTest, ObserversNotifiedOfSsrcBoundtoMidWhenSsrcChanges) {
const std::string mid = "v";
constexpr uint32_t ssrc1 = 10;
constexpr uint32_t ssrc2 = 11;
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
InSequence seq;
EXPECT_CALL(observer, OnSsrcBoundToMid(mid, ssrc1)).Times(1);
EXPECT_CALL(observer, OnSsrcBoundToMid(mid, ssrc2)).Times(1);
auto p1 = CreatePacketWithSsrcMid(ssrc1, mid);
demuxer_.OnRtpPacket(*p1);
auto p2 = CreatePacketWithSsrcMid(ssrc2, mid);
demuxer_.OnRtpPacket(*p2);
}
TEST_F(RtpDemuxerTest, DeregisteredRsidObserversNotInformedOfResolutions) {
constexpr uint32_t ssrc = 111;
const std::string rsid = "a";
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyRsid(rsid, &sink);
// Register several, then deregister only one, to show that not all of the
// observers had been forgotten when one was removed.
MockSsrcBindingObserver observer_1;
MockSsrcBindingObserver observer_2_removed;
MockSsrcBindingObserver observer_3;
RegisterSsrcBindingObserver(&observer_1);
RegisterSsrcBindingObserver(&observer_2_removed);
RegisterSsrcBindingObserver(&observer_3);
DeregisterSsrcBindingObserver(&observer_2_removed);
EXPECT_CALL(observer_1, OnSsrcBoundToRsid(rsid, ssrc)).Times(1);
EXPECT_CALL(observer_2_removed, OnSsrcBoundToRsid(_, _)).Times(0);
EXPECT_CALL(observer_3, OnSsrcBoundToRsid(rsid, ssrc)).Times(1);
// The expected calls to OnSsrcBoundToRsid() will be triggered by this.
demuxer_.OnRtpPacket(*CreatePacketWithSsrcRsid(ssrc, rsid));
}
TEST_F(RtpDemuxerTest,
PacketFittingBothRsidSinkAndSsrcSinkTriggersResolutionCallbacks) {
constexpr uint32_t ssrc = 111;
NiceMock<MockRtpPacketSink> ssrc_sink;
AddSinkOnlySsrc(ssrc, &ssrc_sink);
const std::string rsid = "a";
NiceMock<MockRtpPacketSink> rsid_sink;
AddSinkOnlyRsid(rsid, &rsid_sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(observer, OnSsrcBoundToRsid(rsid, ssrc)).Times(1);
demuxer_.OnRtpPacket(*packet);
}
TEST_F(RtpDemuxerTest, MaliciousPeerCannotCauseMemoryOveruse) {
const std::string mid = "v";
NiceMock<MockRtpPacketSink> sink;
AddSinkOnlyMid(mid, &sink);
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
EXPECT_CALL(observer, OnSsrcBoundToMid(_, _))
.Times(AtMost(RtpDemuxer::kMaxSsrcBindings));
for (int i = 0; i < RtpDemuxer::kMaxSsrcBindings + 1; i++) {
auto packet = CreatePacketWithSsrcMid(i, mid);
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(RtpDemuxerTest, CriteriaMustBeNonEmpty) {
MockRtpPacketSink sink;
RtpDemuxerCriteria criteria;
EXPECT_DEATH(AddSink(criteria, &sink), "");
}
TEST_F(RtpDemuxerTest, RsidMustBeAlphaNumeric) {
MockRtpPacketSink sink;
EXPECT_DEATH(AddSinkOnlyRsid("a_3", &sink), "");
}
TEST_F(RtpDemuxerTest, MidMustBeAlphaNumeric) {
MockRtpPacketSink sink;
EXPECT_DEATH(AddSinkOnlyMid("a_3", &sink), "");
}
TEST_F(RtpDemuxerTest, RsidMustNotExceedMaximumLength) {
MockRtpPacketSink sink;
std::string rsid(StreamId::kMaxSize + 1, 'a');
EXPECT_DEATH(AddSinkOnlyRsid(rsid, &sink), "");
}
TEST_F(RtpDemuxerTest, MidMustNotExceedMaximumLength) {
MockRtpPacketSink sink;
std::string mid(Mid::kMaxSize + 1, 'a');
EXPECT_DEATH(AddSinkOnlyMid(mid, &sink), "");
}
TEST_F(RtpDemuxerTest, DoubleRegisterationOfSsrcBindingObserverDisallowed) {
MockSsrcBindingObserver observer;
RegisterSsrcBindingObserver(&observer);
EXPECT_DEATH(RegisterSsrcBindingObserver(&observer), "");
}
TEST_F(RtpDemuxerTest,
DregisterationOfNeverRegisteredSsrcBindingObserverDisallowed) {
MockSsrcBindingObserver observer;
EXPECT_DEATH(DeregisterSsrcBindingObserver(&observer), "");
}
#endif
} // namespace
} // namespace webrtc