/* * 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.
*/
using ::testing::_; using ::testing::AtLeast; using ::testing::InSequence; using ::testing::NiceMock;
class RtpDemuxerTest : public ::testing::Test { protected:
~RtpDemuxerTest() { for (auto* sink : sinks_to_tear_down_) {
demuxer_.RemoveSink(sink);
}
}
// 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.
// 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 = std::make_unique<RtpPacketReceived>(extension_manager);
packet->SetSsrc(ssrc);
packet->SetSequenceNumber(next_sequence_number_++); return packet;
}
// 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));
}
// 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;
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));
}
}
// 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));
}
}
// The removed sink does not get callbacks. auto packet = CreatePacketWithSsrc(ssrc);
EXPECT_CALL(sink, OnRtpPacket(_)).Times(0); // Not called.
EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
}
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));
}
// 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 (constauto& packet : packets) {
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
} for (constauto& packet : packets) {
EXPECT_TRUE(demuxer_.OnRtpPacket(*packet));
}
}
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);
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);
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";
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";
auto packet = CreatePacketWithSsrcRsid(ssrc, rsid);
EXPECT_CALL(sink, OnRtpPacket(SamePacketAs(*packet))).Times(1);
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);
// 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);
// 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_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);
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;
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;
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;
// 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;
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;
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";
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";
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;
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;
// 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;
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";
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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.