зеркало из https://github.com/mozilla/gecko-dev.git
1291 строка
42 KiB
C++
1291 строка
42 KiB
C++
/*
|
|
* 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/test/mock_rtp_packet_sink_interface.h"
|
|
#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 "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
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.
|
|
|
|
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);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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_;
|
|
uint16_t next_sequence_number_ = 1;
|
|
};
|
|
|
|
class RtpDemuxerDeathTest : public RtpDemuxerTest {};
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
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));
|
|
}
|
|
|
|
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
|
|
|
TEST_F(RtpDemuxerDeathTest, CriteriaMustBeNonEmpty) {
|
|
MockRtpPacketSink sink;
|
|
RtpDemuxerCriteria criteria;
|
|
EXPECT_DEATH(AddSink(criteria, &sink), "");
|
|
}
|
|
|
|
TEST_F(RtpDemuxerDeathTest, RsidMustBeAlphaNumeric) {
|
|
MockRtpPacketSink sink;
|
|
EXPECT_DEATH(AddSinkOnlyRsid("a_3", &sink), "");
|
|
}
|
|
|
|
TEST_F(RtpDemuxerDeathTest, MidMustBeToken) {
|
|
MockRtpPacketSink sink;
|
|
EXPECT_DEATH(AddSinkOnlyMid("a(3)", &sink), "");
|
|
}
|
|
|
|
TEST_F(RtpDemuxerDeathTest, RsidMustNotExceedMaximumLength) {
|
|
MockRtpPacketSink sink;
|
|
std::string rsid(BaseRtpStringExtension::kMaxValueSizeBytes + 1, 'a');
|
|
EXPECT_DEATH(AddSinkOnlyRsid(rsid, &sink), "");
|
|
}
|
|
|
|
TEST_F(RtpDemuxerDeathTest, MidMustNotExceedMaximumLength) {
|
|
MockRtpPacketSink sink;
|
|
std::string mid(BaseRtpStringExtension::kMaxValueSizeBytes + 1, 'a');
|
|
EXPECT_DEATH(AddSinkOnlyMid(mid, &sink), "");
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|