Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(892)

Unified Diff: webrtc/pc/mediasession_unittest.cc

Issue 1956343002: Initial asymmetric codec support in MediaSessionDescription (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added TODO. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/pc/mediasession.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/pc/mediasession_unittest.cc
diff --git a/webrtc/pc/mediasession_unittest.cc b/webrtc/pc/mediasession_unittest.cc
index b1c4044b707699f88125ec2696534e597b952c9a..7076c7f5c522ef9e4eba13e4eb1f3f3a95583520 100644
--- a/webrtc/pc/mediasession_unittest.cc
+++ b/webrtc/pc/mediasession_unittest.cc
@@ -39,6 +39,7 @@ typedef std::vector<cricket::Candidate> Candidates;
using cricket::MediaContentDescription;
using cricket::MediaSessionDescriptionFactory;
+using cricket::MediaContentDirection;
using cricket::MediaSessionOptions;
using cricket::MediaType;
using cricket::SessionDescription;
@@ -211,10 +212,12 @@ class MediaSessionDescriptionFactoryTest : public testing::Test {
MediaSessionDescriptionFactoryTest()
: f1_(&tdf1_),
f2_(&tdf2_) {
- f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
+ f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
+ MAKE_VECTOR(kAudioCodecs1));
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
- f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
+ f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
+ MAKE_VECTOR(kAudioCodecs2));
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
tdf1_.set_certificate(rtc::RTCCertificate::Create(
@@ -862,6 +865,9 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
}
+// TODO(deadbeef): Extend these tests to ensure the correct direction with other
+// answerer settings.
+
// This test that the media direction is set to send/receive in an answer if
// the offer is send receive.
TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
@@ -2395,10 +2401,12 @@ TEST_F(MediaSessionDescriptionFactoryTest,
class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
public:
MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
- f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
+ f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
+ MAKE_VECTOR(kAudioCodecs1));
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
- f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
+ f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
+ MAKE_VECTOR(kAudioCodecs2));
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
f1_.set_secure(SEC_ENABLED);
@@ -2450,3 +2458,304 @@ INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
MediaProtocolTest,
::testing::ValuesIn(kMediaProtocolsDtls));
+
+TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
+ TransportDescriptionFactory tdf;
+ MediaSessionDescriptionFactory sf(&tdf);
+ std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
+ std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
+
+ // The merged list of codecs should contain any send codecs that are also
+ // nominally in the recieve codecs list. Payload types should be picked from
+ // the send codecs and a number-of-channels of 0 and 1 should be equivalent
+ // (set to 1). This equals what happens when the send codecs are used in an
+ // offer and the receive codecs are used in the following answer.
+ const std::vector<AudioCodec> sendrecv_codecs =
+ MAKE_VECTOR(kAudioCodecsAnswer);
+ const std::vector<AudioCodec> no_codecs;
+
+ RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
+ << "Please don't change shared test data!";
+ RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
+ << "Please don't change shared test data!";
+ // Alter iLBC send codec to have zero channels, to test that that is handled
+ // properly.
+ send_codecs[1].channels = 0;
+
+ // Alther iLBC receive codec to be lowercase, to test that case conversions
+ // are handled properly.
+ recv_codecs[2].name = "ilbc";
+
+ // Test proper merge
+ sf.set_audio_codecs(send_codecs, recv_codecs);
+ EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
+ EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
+ EXPECT_TRUE(sf.audio_codecs() == sendrecv_codecs);
+
+ // Test empty send codecs list
+ sf.set_audio_codecs(no_codecs, recv_codecs);
+ EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
+ EXPECT_TRUE(sf.audio_recv_codecs() == recv_codecs);
+ EXPECT_TRUE(sf.audio_codecs() == no_codecs);
+
+ // Test empty recv codecs list
+ sf.set_audio_codecs(send_codecs, no_codecs);
+ EXPECT_TRUE(sf.audio_send_codecs() == send_codecs);
+ EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
+ EXPECT_TRUE(sf.audio_codecs() == no_codecs);
+
+ // Test all empty codec lists
+ sf.set_audio_codecs(no_codecs, no_codecs);
+ EXPECT_TRUE(sf.audio_send_codecs() == no_codecs);
+ EXPECT_TRUE(sf.audio_recv_codecs() == no_codecs);
+ EXPECT_TRUE(sf.audio_codecs() == no_codecs);
+}
+
+namespace {
+void TestAudioCodecsOffer(MediaContentDirection direction,
+ bool add_legacy_stream) {
+ TransportDescriptionFactory tdf;
+ MediaSessionDescriptionFactory sf(&tdf);
+ const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
+ const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
+ const std::vector<AudioCodec> sendrecv_codecs =
+ MAKE_VECTOR(kAudioCodecsAnswer);
+ sf.set_audio_codecs(send_codecs, recv_codecs);
+ sf.set_add_legacy_streams(add_legacy_stream);
+
+ MediaSessionOptions opts;
+ opts.recv_audio = (direction == cricket::MD_RECVONLY ||
+ direction == cricket::MD_SENDRECV);
+ opts.recv_video = false;
+ if (direction == cricket::MD_SENDONLY || direction == cricket::MD_SENDRECV)
+ opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
+
+ std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
+ ASSERT_TRUE(offer.get() != NULL);
+ const ContentInfo* ac = offer->GetContentByName("audio");
+
+ // If the factory didn't add any audio content to the offer, we cannot check
+ // that the codecs put in are right. This happens when we neither want to send
+ // nor receive audio. The checks are still in place if at some point we'd
+ // instead create an inactive stream.
+ if (ac) {
+ AudioContentDescription* acd =
+ static_cast<AudioContentDescription*>(ac->description);
+ // sendrecv and inactive should both present lists as if the channel was to
+ // be used for sending and receiving. Inactive essentially means it might
+ // eventually be used anything, but we don't know more at this moment.
+ if (acd->direction() == cricket::MD_SENDONLY) {
+ EXPECT_TRUE(acd->codecs() == send_codecs);
+ } else if (acd->direction() == cricket::MD_RECVONLY) {
+ EXPECT_TRUE(acd->codecs() == recv_codecs);
+ } else {
+ EXPECT_TRUE(acd->codecs() == sendrecv_codecs);
+ }
+ }
+}
+
+static const AudioCodec kOfferAnswerCodecs[] = {
+ AudioCodec(0, "codec0", 16000, -1, 1),
+ AudioCodec(1, "codec1", 8000, 13300, 1),
+ AudioCodec(2, "codec2", 8000, 64000, 1),
+ AudioCodec(3, "codec3", 8000, 64000, 1),
+ AudioCodec(4, "codec4", 8000, 0, 2),
+ AudioCodec(5, "codec5", 32000, 0, 1),
+ AudioCodec(6, "codec6", 48000, 0, 1)
+};
+
+
+/* The codecs groups below are chosen as per the matrix below. The objective is
+ * to have different sets of codecs in the inputs, to get unique sets of codecs
+ * after negotiation, depending on offer and answer communication directions.
+ * One-way directions in the offer should either result in the opposite
+ * direction in the answer, or an inactive answer. Regardless, the choice of
+ * codecs should be as if the answer contained the opposite direction.
+ * Inactive offers should be treated as sendrecv/sendrecv.
+ *
+ * | Offer | Answer | Result
+ * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
+ * 0 | x - - | - x - | x - - - -
+ * 1 | x x x | - x - | x - - x -
+ * 2 | - x - | x - - | - x - - -
+ * 3 | x x x | x - - | - x x - -
+ * 4 | - x - | x x x | - x - - -
+ * 5 | x - - | x x x | x - - - -
+ * 6 | x x x | x x x | x x x x x
+ */
+// Codecs used by offerer in the AudioCodecsAnswerTest
+static const int kOfferSendCodecs[] = { 0, 1, 3, 5, 6 };
+static const int kOfferRecvCodecs[] = { 1, 2, 3, 4, 6 };
+// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
+// jumbled to catch the answer not following the order in the offer.
+static const int kAnswerSendCodecs[] = { 6, 5, 2, 3, 4 };
+static const int kAnswerRecvCodecs[] = { 6, 5, 4, 1, 0 };
+// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
+static const int kResultSend_RecvCodecs[] = { 0, 1, 5, 6 };
+static const int kResultRecv_SendCodecs[] = { 2, 3, 4, 6 };
+static const int kResultSendrecv_SendCodecs[] = { 3, 6 };
+static const int kResultSendrecv_RecvCodecs[] = { 1, 6 };
+static const int kResultSendrecv_SendrecvCodecs[] = { 6 };
+
+template <typename T, int IDXS>
+std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
+ std::vector<T> out;
+ out.reserve(IDXS);
+ for (int idx : indices)
+ out.push_back(array[idx]);
+
+ return out;
+}
+
+void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
+ MediaContentDirection answer_direction,
+ bool add_legacy_stream) {
+ TransportDescriptionFactory offer_tdf;
+ TransportDescriptionFactory answer_tdf;
+ MediaSessionDescriptionFactory offer_factory(&offer_tdf);
+ MediaSessionDescriptionFactory answer_factory(&answer_tdf);
+ offer_factory.set_audio_codecs(
+ VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
+ VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
+ answer_factory.set_audio_codecs(
+ VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
+ VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
+
+ // Never add a legacy stream to offer - we want to control the offer
+ // parameters exactly.
+ offer_factory.set_add_legacy_streams(false);
+ answer_factory.set_add_legacy_streams(add_legacy_stream);
+ MediaSessionOptions offer_opts;
+ offer_opts.recv_audio = (offer_direction == cricket::MD_RECVONLY ||
+ offer_direction == cricket::MD_SENDRECV);
+ offer_opts.recv_video = false;
+ if (offer_direction == cricket::MD_SENDONLY ||
+ offer_direction == cricket::MD_SENDRECV) {
+ offer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
+ }
+
+ std::unique_ptr<SessionDescription> offer(
+ offer_factory.CreateOffer(offer_opts, NULL));
+ ASSERT_TRUE(offer.get() != NULL);
+
+ MediaSessionOptions answer_opts;
+ answer_opts.recv_audio = (answer_direction == cricket::MD_RECVONLY ||
+ answer_direction == cricket::MD_SENDRECV);
+ answer_opts.recv_video = false;
+ if (answer_direction == cricket::MD_SENDONLY ||
+ answer_direction == cricket::MD_SENDRECV) {
+ answer_opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
+ }
+ std::unique_ptr<SessionDescription> answer(
+ answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
+ const ContentInfo* ac = answer->GetContentByName("audio");
+
+ // If the factory didn't add any audio content to the answer, we cannot check
+ // that the codecs put in are right. This happens when we neither want to send
+ // nor receive audio. The checks are still in place if at some point we'd
+ // instead create an inactive stream.
+ if (ac) {
+ const AudioContentDescription* acd =
+ static_cast<const AudioContentDescription*>(ac->description);
+ EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
+
+
+ std::vector<AudioCodec> target_codecs;
+ // For offers with sendrecv or inactive, we should never reply with more
+ // codecs than offered, with these codec sets.
+ switch (offer_direction) {
+ case cricket::MD_INACTIVE:
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultSendrecv_SendrecvCodecs);
+ break;
+ case cricket::MD_SENDONLY:
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultSend_RecvCodecs);
+ break;
+ case cricket::MD_RECVONLY:
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultRecv_SendCodecs);
+ break;
+ case cricket::MD_SENDRECV:
+ if (acd->direction() == cricket::MD_SENDONLY) {
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultSendrecv_SendCodecs);
+ } else if (acd->direction() == cricket::MD_RECVONLY) {
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultSendrecv_RecvCodecs);
+ } else {
+ target_codecs = VectorFromIndices(kOfferAnswerCodecs,
+ kResultSendrecv_SendrecvCodecs);
+ }
+ break;
+ }
+
+ auto format_codecs = [] (const std::vector<AudioCodec>& codecs) {
+ std::stringstream os;
+ bool first = true;
+ os << "{";
+ for (const auto& c : codecs) {
+ os << (first ? " " : ", ") << c.id;
+ first = false;
+ }
+ os << " }";
+ return os.str();
+ };
+
+ EXPECT_TRUE(acd->codecs() == target_codecs)
+ << "Expected: " << format_codecs(target_codecs)
+ << ", got: " << format_codecs(acd->codecs())
+ << "; Offered: " << MediaContentDirectionToString(offer_direction)
+ << ", answerer wants: "
+ << MediaContentDirectionToString(answer_direction)
+ << "; got: " << MediaContentDirectionToString(acd->direction());
+ } else {
+ EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
+ << "Only inactive offers are allowed to not generate any audio content";
+ }
+}
+}
+
+class AudioCodecsOfferTest
+ : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
+ bool>> {
+};
+
+TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
+ TestAudioCodecsOffer(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
+ AudioCodecsOfferTest,
+ ::testing::Combine(
+ ::testing::Values(cricket::MD_SENDONLY,
+ cricket::MD_RECVONLY,
+ cricket::MD_SENDRECV,
+ cricket::MD_INACTIVE),
+ ::testing::Bool()));
+
+class AudioCodecsAnswerTest
+ : public ::testing::TestWithParam<std::tr1::tuple<MediaContentDirection,
+ MediaContentDirection,
+ bool>> {
+};
+
+TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
+ TestAudioCodecsAnswer(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()),
+ std::tr1::get<2>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
+ AudioCodecsAnswerTest,
+ ::testing::Combine(
+ ::testing::Values(cricket::MD_SENDONLY,
+ cricket::MD_RECVONLY,
+ cricket::MD_SENDRECV,
+ cricket::MD_INACTIVE),
+ ::testing::Values(cricket::MD_SENDONLY,
+ cricket::MD_RECVONLY,
+ cricket::MD_SENDRECV,
+ cricket::MD_INACTIVE),
+ ::testing::Bool()));
« no previous file with comments | « webrtc/pc/mediasession.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698