Bug 1967189 - Track duplicate payload types for all recv tracks in a peer connection. r=bwc,dbaker
Two issues are fixed here: - The lists of unique and duplicate payload types were never reset, so would accumulate entries across renegotiations - The std::map could only store distinct payload types, and only a single track per payload type. Therefore, at most one track could ever know about any given duplicate payload type. This patch also adds some unittests for JsepTrack::SetUniqueReceivePayloadTypes. They're very verbose, for now, to enable landing this patch quickly. Differential Revision: https://phabricator.services.mozilla.com/D250095
This commit is contained in:
committed by
pehrsons@gmail.com
parent
4f622a88c7
commit
1e511bf3af
@@ -733,11 +733,13 @@ nsresult JsepTrack::Negotiate(const SdpMediaSection& answer,
|
||||
/* static */
|
||||
void JsepTrack::SetUniqueReceivePayloadTypes(std::vector<JsepTrack*>& tracks,
|
||||
bool localOffer) {
|
||||
// Maps to track details if no other track contains the payload type,
|
||||
// otherwise maps to nullptr.
|
||||
std::map<uint16_t, std::tuple<JsepTrack*, bool>> payloadTypeToDetailsMap;
|
||||
// Maps payload types to all tracks that have negotiated them.
|
||||
std::multimap<uint16_t, JsepTrack*> payloadTypeToTracks;
|
||||
|
||||
for (JsepTrack* track : tracks) {
|
||||
track->mUniqueReceivePayloadTypes.clear();
|
||||
track->mDuplicateReceivePayloadTypes.clear();
|
||||
|
||||
if (track->GetMediaType() == SdpMediaSection::kApplication) {
|
||||
continue;
|
||||
}
|
||||
@@ -755,24 +757,23 @@ void JsepTrack::SetUniqueReceivePayloadTypes(std::vector<JsepTrack*>& tracks,
|
||||
}
|
||||
|
||||
for (uint16_t pt : payloadTypesForTrack) {
|
||||
payloadTypeToDetailsMap[pt] =
|
||||
std::make_tuple(track, !payloadTypeToDetailsMap.count(pt));
|
||||
payloadTypeToTracks.insert({pt, track});
|
||||
}
|
||||
}
|
||||
|
||||
for (auto ptAndDetails : payloadTypeToDetailsMap) {
|
||||
uint16_t uniquePt = ptAndDetails.first;
|
||||
MOZ_ASSERT(uniquePt <= UINT8_MAX);
|
||||
auto* trackDetails = std::get<JsepTrack*>(ptAndDetails.second);
|
||||
|
||||
if (trackDetails) {
|
||||
if (std::get<bool>(ptAndDetails.second)) {
|
||||
trackDetails->mUniqueReceivePayloadTypes.push_back(
|
||||
static_cast<uint8_t>(uniquePt));
|
||||
} else {
|
||||
trackDetails->mDuplicateReceivePayloadTypes.push_back(
|
||||
static_cast<uint8_t>(uniquePt));
|
||||
}
|
||||
for (auto it = payloadTypeToTracks.begin(), end = payloadTypeToTracks.end();
|
||||
it != end;) {
|
||||
const auto& [key, firstTrackForPt] = *it;
|
||||
const auto pt = AssertedCast<uint8_t>(key);
|
||||
const size_t count = payloadTypeToTracks.count(key);
|
||||
if (count == 1) {
|
||||
firstTrackForPt->mUniqueReceivePayloadTypes.push_back(pt);
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
for (auto next = payloadTypeToTracks.upper_bound(key); it != next; ++it) {
|
||||
const auto& [_pt, track] = *it;
|
||||
track->mDuplicateReceivePayloadTypes.push_back(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "CodecConfig.h"
|
||||
@@ -24,6 +25,8 @@
|
||||
#include "jsep/JsepSession.h"
|
||||
#include "jsep/JsepSessionImpl.h"
|
||||
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
namespace mozilla {
|
||||
MOZ_RUNINIT static std::string kAEqualsCandidate("a=candidate:");
|
||||
const static size_t kNumCandidatesPerComponent = 3;
|
||||
@@ -4972,55 +4975,65 @@ TEST_F(JsepSessionTest, TestUniqueReceivePayloadTypes) {
|
||||
|
||||
ASSERT_FALSE(IsNull(offerTransceivers[0].mRecvTrack));
|
||||
ASSERT_TRUE(offerTransceivers[0].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
offerTransceivers[0].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(offerTransceivers[0].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(offerTransceivers[0].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(0, 8, 9, 101, 109));
|
||||
|
||||
ASSERT_FALSE(IsNull(offerTransceivers[1].mRecvTrack));
|
||||
ASSERT_TRUE(offerTransceivers[1].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
offerTransceivers[1].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(offerTransceivers[1].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(offerTransceivers[1].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(0, 8, 9, 101, 109));
|
||||
|
||||
// First video transceiver is the only one receiving, so gets unique pts.
|
||||
ASSERT_FALSE(IsNull(offerTransceivers[2].mRecvTrack));
|
||||
ASSERT_TRUE(offerTransceivers[2].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_NE(
|
||||
0U,
|
||||
offerTransceivers[2].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(offerTransceivers[2].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre(97, 99, 103, 105, 120, 121, 122, 123, 126));
|
||||
ASSERT_THAT(offerTransceivers[2].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
|
||||
// First video transceiver is not receiving, so does not get unique pts.
|
||||
ASSERT_TRUE(IsNull(offerTransceivers[3].mRecvTrack));
|
||||
ASSERT_TRUE(offerTransceivers[3].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
offerTransceivers[3].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(offerTransceivers[3].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(offerTransceivers[3].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(97, 99, 103, 105, 120, 121, 122, 123, 126));
|
||||
|
||||
ASSERT_FALSE(IsNull(answerTransceivers[0].mRecvTrack));
|
||||
ASSERT_TRUE(answerTransceivers[0].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
answerTransceivers[0].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(answerTransceivers[0].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(
|
||||
answerTransceivers[0].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(0, 8, 9, 101, 109));
|
||||
|
||||
ASSERT_FALSE(IsNull(answerTransceivers[1].mRecvTrack));
|
||||
ASSERT_TRUE(answerTransceivers[1].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
answerTransceivers[1].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(answerTransceivers[1].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(
|
||||
answerTransceivers[1].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(0, 8, 9, 101, 109));
|
||||
|
||||
// Answerer is receiving two video streams with the same payload types.
|
||||
// Neither recv track should have unique pts.
|
||||
ASSERT_FALSE(IsNull(answerTransceivers[2].mRecvTrack));
|
||||
ASSERT_TRUE(answerTransceivers[2].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
answerTransceivers[2].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(answerTransceivers[2].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(
|
||||
answerTransceivers[2].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(97, 99, 103, 105, 120, 121, 122, 123, 126));
|
||||
|
||||
ASSERT_FALSE(IsNull(answerTransceivers[3].mRecvTrack));
|
||||
ASSERT_TRUE(answerTransceivers[3].mRecvTrack.GetNegotiatedDetails());
|
||||
ASSERT_EQ(
|
||||
0U,
|
||||
answerTransceivers[3].mRecvTrack.GetUniqueReceivePayloadTypes().size());
|
||||
ASSERT_THAT(answerTransceivers[3].mRecvTrack.GetUniqueReceivePayloadTypes(),
|
||||
UnorderedElementsAre());
|
||||
ASSERT_THAT(
|
||||
answerTransceivers[3].mRecvTrack.GetDuplicateReceivePayloadTypes(),
|
||||
UnorderedElementsAre(97, 99, 103, 105, 120, 121, 122, 123, 126));
|
||||
}
|
||||
|
||||
TEST_F(JsepSessionTest, UnknownFingerprintAlgorithm) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "ssl.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "MockJsepCodecPreferences.h"
|
||||
@@ -17,6 +18,8 @@
|
||||
#include "sdp/SipccSdpParser.h"
|
||||
#include "sdp/SdpHelper.h"
|
||||
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class JsepTrackTestBase : public ::testing::Test {
|
||||
@@ -1790,4 +1793,380 @@ TEST_F(JsepTrackTest, NonDefaultVideoSdpFmtpLine) {
|
||||
EXPECT_EQ("nothing", codec->mSdpFmtpLine.valueOr("nothing"));
|
||||
}
|
||||
|
||||
TEST(JsepTrackRecvPayloadTypesTest, SingleTrackPTsAreUnique)
|
||||
{
|
||||
constexpr auto audio = SdpMediaSection::MediaType::kAudio;
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs;
|
||||
codecs.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
|
||||
SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer1Msection1 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer1Msection1 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection1);
|
||||
}
|
||||
|
||||
JsepTrack t1{audio, sdp::Direction::kRecv};
|
||||
t1.PopulateCodecs(codecs, false);
|
||||
t1.RecvTrackSetLocal(offer1Msection1);
|
||||
t1.RecvTrackSetRemote(answer1, answer1Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1),
|
||||
NS_OK);
|
||||
|
||||
std::vector tracks{&t1};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(tracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsAreUnique)
|
||||
{
|
||||
constexpr auto audio = SdpMediaSection::MediaType::kAudio;
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs1;
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs2;
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("2", "codec1", 48000, 1, true));
|
||||
|
||||
SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer1Msection1 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& offer1Msection2 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer1Msection1 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& answer1Msection2 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs1) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection1);
|
||||
}
|
||||
|
||||
for (const auto& codec : codecs2) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection2);
|
||||
}
|
||||
|
||||
JsepTrack t1{audio, sdp::Direction::kRecv};
|
||||
t1.PopulateCodecs(codecs1, false);
|
||||
t1.RecvTrackSetLocal(offer1Msection1);
|
||||
t1.RecvTrackSetRemote(answer1, answer1Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1),
|
||||
NS_OK);
|
||||
|
||||
JsepTrack t2{audio, sdp::Direction::kRecv};
|
||||
t2.PopulateCodecs(codecs2, false);
|
||||
t2.RecvTrackSetLocal(offer1Msection2);
|
||||
t2.RecvTrackSetRemote(answer1, answer1Msection2);
|
||||
ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2),
|
||||
NS_OK);
|
||||
|
||||
std::vector tracks{&t1, &t2};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(tracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(2));
|
||||
EXPECT_THAT(t2.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre());
|
||||
}
|
||||
|
||||
TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsAreDuplicates)
|
||||
{
|
||||
constexpr auto audio = SdpMediaSection::MediaType::kAudio;
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs1;
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs2;
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
|
||||
SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer1Msection1 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& offer1Msection2 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer1Msection1 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& answer1Msection2 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs1) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection1);
|
||||
}
|
||||
for (const auto& codec : codecs2) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection2);
|
||||
}
|
||||
|
||||
JsepTrack t1{audio, sdp::Direction::kRecv};
|
||||
t1.PopulateCodecs(codecs1, false);
|
||||
t1.RecvTrackSetLocal(offer1Msection1);
|
||||
t1.RecvTrackSetRemote(answer1, answer1Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1),
|
||||
NS_OK);
|
||||
|
||||
JsepTrack t2{audio, sdp::Direction::kRecv};
|
||||
t2.PopulateCodecs(codecs2, false);
|
||||
t2.RecvTrackSetLocal(offer1Msection2);
|
||||
t2.RecvTrackSetRemote(answer1, answer1Msection2);
|
||||
ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2),
|
||||
NS_OK);
|
||||
|
||||
std::vector tracks{&t1, &t2};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(tracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t2.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
}
|
||||
|
||||
TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsOverlap)
|
||||
{
|
||||
constexpr auto audio = SdpMediaSection::MediaType::kAudio;
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs1;
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("2", "codec2", 48000, 1, true));
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs2;
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("3", "codec2", 48000, 1, true));
|
||||
|
||||
SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer1Msection1 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& offer1Msection2 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer1Msection1 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& answer1Msection2 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs1) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection1);
|
||||
}
|
||||
|
||||
for (const auto& codec : codecs2) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection2);
|
||||
}
|
||||
|
||||
JsepTrack t1{audio, sdp::Direction::kRecv};
|
||||
t1.PopulateCodecs(codecs1, false);
|
||||
t1.RecvTrackSetLocal(offer1Msection1);
|
||||
t1.RecvTrackSetRemote(answer1, answer1Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1),
|
||||
NS_OK);
|
||||
|
||||
JsepTrack t2{audio, sdp::Direction::kRecv};
|
||||
t2.PopulateCodecs(codecs2, false);
|
||||
t2.RecvTrackSetLocal(offer1Msection2);
|
||||
t2.RecvTrackSetRemote(answer1, answer1Msection2);
|
||||
ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2),
|
||||
NS_OK);
|
||||
|
||||
std::vector tracks{&t1, &t2};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(tracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(2));
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(3));
|
||||
EXPECT_THAT(t2.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1));
|
||||
}
|
||||
|
||||
TEST(JsepTrackRecvPayloadTypesTest, DoubleTrackPTsDuplicateAfterRenegotiation)
|
||||
{
|
||||
constexpr auto audio = SdpMediaSection::MediaType::kAudio;
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs1;
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("1", "codec1", 48000, 1, true));
|
||||
codecs1.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("2", "codec2", 48000, 1, true));
|
||||
|
||||
std::vector<UniquePtr<JsepCodecDescription>> codecs2;
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("3", "codec1", 48000, 1, true));
|
||||
codecs2.emplace_back(
|
||||
MakeUnique<JsepAudioCodecDescription>("4", "codec2", 48000, 1, true));
|
||||
|
||||
// First negotiation.
|
||||
SipccSdp offer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer1Msection1 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& offer1Msection2 = offer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer1(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer1Msection1 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& answer1Msection2 = answer1.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs1) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection1);
|
||||
}
|
||||
|
||||
for (const auto& codec : codecs2) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer1Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer1Msection2);
|
||||
}
|
||||
|
||||
// t1 and t2 use distinct payload types in the first negotiation.
|
||||
JsepTrack t1{audio, sdp::Direction::kRecv};
|
||||
t1.PopulateCodecs(codecs1, false);
|
||||
t1.RecvTrackSetLocal(offer1Msection1);
|
||||
t1.RecvTrackSetRemote(answer1, answer1Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer1Msection1, answer1Msection1, offer1Msection1),
|
||||
NS_OK);
|
||||
|
||||
JsepTrack t2{audio, sdp::Direction::kRecv};
|
||||
t2.PopulateCodecs(codecs2, false);
|
||||
t2.RecvTrackSetLocal(offer1Msection2);
|
||||
t2.RecvTrackSetRemote(answer1, answer1Msection2);
|
||||
ASSERT_EQ(t2.Negotiate(answer1Msection2, answer1Msection2, offer1Msection2),
|
||||
NS_OK);
|
||||
|
||||
std::vector tracks{&t1, &t2};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(tracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(1, 2));
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre(3, 4));
|
||||
EXPECT_THAT(t2.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre());
|
||||
|
||||
// Second negotiation.
|
||||
SipccSdp offer2(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& offer2Msection1 = offer2.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& offer2Msection2 = offer2.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kRecvonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
SipccSdp answer2(SdpOrigin("", 0, 0, sdp::kIPv4, ""));
|
||||
SdpMediaSection& answer2Msection1 = answer2.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
SdpMediaSection& answer2Msection2 = answer2.AddMediaSection(
|
||||
audio, SdpDirectionAttribute::kSendonly, 0,
|
||||
SdpHelper::GetProtocolForMediaType(audio), sdp::kIPv4, "0.0.0.0");
|
||||
|
||||
for (const auto& codec : codecs1) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer2Msection1.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer2Msection1);
|
||||
}
|
||||
|
||||
for (const auto& codec : codecs2) {
|
||||
codec->mDirection = sdp::kSend;
|
||||
offer2Msection2.AddCodec(codec->mDefaultPt, codec->mName, codec->mClock,
|
||||
codec->mChannels);
|
||||
auto clone = WrapUnique(codec->Clone());
|
||||
clone->mDirection = sdp::kRecv;
|
||||
clone->AddToMediaSection(answer2Msection2);
|
||||
}
|
||||
|
||||
t1.PopulateCodecs(codecs1, false);
|
||||
t1.RecvTrackSetLocal(offer2Msection1);
|
||||
t1.RecvTrackSetRemote(answer2, answer2Msection1);
|
||||
ASSERT_EQ(t1.Negotiate(answer2Msection1, answer2Msection1, offer2Msection1),
|
||||
NS_OK);
|
||||
|
||||
// Change t2 to use the same payload types as t1. Both tracks should now mark
|
||||
// all their payload types as duplicates.
|
||||
t2.PopulateCodecs(codecs1, false);
|
||||
t2.RecvTrackSetLocal(offer2Msection2);
|
||||
t2.RecvTrackSetRemote(answer2, answer2Msection2);
|
||||
ASSERT_EQ(t2.Negotiate(answer2Msection2, answer2Msection2, offer2Msection2),
|
||||
NS_OK);
|
||||
|
||||
std::vector newTracks{&t1, &t2};
|
||||
JsepTrack::SetUniqueReceivePayloadTypes(newTracks);
|
||||
EXPECT_THAT(t1.GetUniqueReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t1.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1, 2));
|
||||
EXPECT_THAT(t2.GetUniqueReceivePayloadTypes(), UnorderedElementsAre());
|
||||
EXPECT_THAT(t2.GetDuplicateReceivePayloadTypes(), UnorderedElementsAre(1, 2));
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
Reference in New Issue
Block a user