1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/streaming/sender_session.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <cstdio>
8*3f982cf4SFabien Sanglard #include <utility>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "cast/streaming/capture_configs.h"
11*3f982cf4SFabien Sanglard #include "cast/streaming/capture_recommendations.h"
12*3f982cf4SFabien Sanglard #include "cast/streaming/mock_environment.h"
13*3f982cf4SFabien Sanglard #include "cast/streaming/testing/simple_message_port.h"
14*3f982cf4SFabien Sanglard #include "gmock/gmock.h"
15*3f982cf4SFabien Sanglard #include "gtest/gtest.h"
16*3f982cf4SFabien Sanglard #include "platform/base/ip_address.h"
17*3f982cf4SFabien Sanglard #include "platform/test/fake_clock.h"
18*3f982cf4SFabien Sanglard #include "platform/test/fake_task_runner.h"
19*3f982cf4SFabien Sanglard #include "util/chrono_helpers.h"
20*3f982cf4SFabien Sanglard #include "util/stringprintf.h"
21*3f982cf4SFabien Sanglard
22*3f982cf4SFabien Sanglard using ::testing::_;
23*3f982cf4SFabien Sanglard using ::testing::InSequence;
24*3f982cf4SFabien Sanglard using ::testing::Invoke;
25*3f982cf4SFabien Sanglard using ::testing::NiceMock;
26*3f982cf4SFabien Sanglard using ::testing::Return;
27*3f982cf4SFabien Sanglard using ::testing::StrictMock;
28*3f982cf4SFabien Sanglard
29*3f982cf4SFabien Sanglard namespace openscreen {
30*3f982cf4SFabien Sanglard namespace cast {
31*3f982cf4SFabien Sanglard
32*3f982cf4SFabien Sanglard namespace {
33*3f982cf4SFabien Sanglard constexpr char kMalformedAnswerMessage[] = R"({
34*3f982cf4SFabien Sanglard "type": "ANSWER",
35*3f982cf4SFabien Sanglard "seqNum": 1,
36*3f982cf4SFabien Sanglard "answer": {
37*3f982cf4SFabien Sanglard "castMode": "mirroring",
38*3f982cf4SFabien Sanglard "udpPort": 1234,
39*3f982cf4SFabien Sanglard "sendIndexes": [1, 3],
40*3f982cf4SFabien Sanglard "ssrcs": [1, 2]
41*3f982cf4SFabien Sanglard })";
42*3f982cf4SFabien Sanglard
43*3f982cf4SFabien Sanglard constexpr char kValidJsonInvalidFormatAnswerMessage[] = R"({
44*3f982cf4SFabien Sanglard "type": "ANSWER",
45*3f982cf4SFabien Sanglard "seqNum": 1,
46*3f982cf4SFabien Sanglard "answer-2": {
47*3f982cf4SFabien Sanglard "castMode": "mirroring",
48*3f982cf4SFabien Sanglard "udpPort": 1234,
49*3f982cf4SFabien Sanglard "sendIndexes": [1, 3],
50*3f982cf4SFabien Sanglard "ssrcs": [1, 2]
51*3f982cf4SFabien Sanglard }
52*3f982cf4SFabien Sanglard })";
53*3f982cf4SFabien Sanglard
54*3f982cf4SFabien Sanglard constexpr char kValidJsonInvalidAnswerMessage[] = R"({
55*3f982cf4SFabien Sanglard "type": "ANSWER",
56*3f982cf4SFabien Sanglard "seqNum": 1,
57*3f982cf4SFabien Sanglard "answer": {
58*3f982cf4SFabien Sanglard "castMode": "mirroring",
59*3f982cf4SFabien Sanglard "udpPort": -1234,
60*3f982cf4SFabien Sanglard "sendIndexes": [1, 3],
61*3f982cf4SFabien Sanglard "ssrcs": [1, 2]
62*3f982cf4SFabien Sanglard }
63*3f982cf4SFabien Sanglard })";
64*3f982cf4SFabien Sanglard
65*3f982cf4SFabien Sanglard constexpr char kMissingAnswerMessage[] = R"({
66*3f982cf4SFabien Sanglard "type": "ANSWER",
67*3f982cf4SFabien Sanglard "seqNum": 1
68*3f982cf4SFabien Sanglard })";
69*3f982cf4SFabien Sanglard
70*3f982cf4SFabien Sanglard constexpr char kInvalidSequenceNumberMessage[] = R"({
71*3f982cf4SFabien Sanglard "type": "ANSWER",
72*3f982cf4SFabien Sanglard "seqNum": "not actually a number"
73*3f982cf4SFabien Sanglard })";
74*3f982cf4SFabien Sanglard
75*3f982cf4SFabien Sanglard constexpr char kUnknownTypeMessage[] = R"({
76*3f982cf4SFabien Sanglard "type": "ANSWER_VERSION_2",
77*3f982cf4SFabien Sanglard "seqNum": 1
78*3f982cf4SFabien Sanglard })";
79*3f982cf4SFabien Sanglard
80*3f982cf4SFabien Sanglard constexpr char kInvalidTypeMessage[] = R"({
81*3f982cf4SFabien Sanglard "type": 39,
82*3f982cf4SFabien Sanglard "seqNum": 1
83*3f982cf4SFabien Sanglard })";
84*3f982cf4SFabien Sanglard
85*3f982cf4SFabien Sanglard constexpr char kInvalidTypeMessageWithNoSeqNum[] = R"({
86*3f982cf4SFabien Sanglard "type": 39
87*3f982cf4SFabien Sanglard })";
88*3f982cf4SFabien Sanglard
89*3f982cf4SFabien Sanglard constexpr char kErrorAnswerMessage[] = R"({
90*3f982cf4SFabien Sanglard "seqNum": 1,
91*3f982cf4SFabien Sanglard "type": "ANSWER",
92*3f982cf4SFabien Sanglard "result": "error",
93*3f982cf4SFabien Sanglard "error": {
94*3f982cf4SFabien Sanglard "code": 123,
95*3f982cf4SFabien Sanglard "description": "something bad happened"
96*3f982cf4SFabien Sanglard }
97*3f982cf4SFabien Sanglard })";
98*3f982cf4SFabien Sanglard
99*3f982cf4SFabien Sanglard constexpr char kCapabilitiesResponse[] = R"({
100*3f982cf4SFabien Sanglard "seqNum": 2,
101*3f982cf4SFabien Sanglard "result": "ok",
102*3f982cf4SFabien Sanglard "type": "CAPABILITIES_RESPONSE",
103*3f982cf4SFabien Sanglard "capabilities": {
104*3f982cf4SFabien Sanglard "mediaCaps": ["video", "vp8", "audio", "aac"]
105*3f982cf4SFabien Sanglard }
106*3f982cf4SFabien Sanglard })";
107*3f982cf4SFabien Sanglard
108*3f982cf4SFabien Sanglard const AudioCaptureConfig kAudioCaptureConfigInvalidChannels{
109*3f982cf4SFabien Sanglard AudioCodec::kAac, -1 /* channels */, 44000 /* bit_rate */,
110*3f982cf4SFabien Sanglard 96000 /* sample_rate */
111*3f982cf4SFabien Sanglard };
112*3f982cf4SFabien Sanglard
113*3f982cf4SFabien Sanglard const AudioCaptureConfig kAudioCaptureConfigValid{
114*3f982cf4SFabien Sanglard AudioCodec::kAac,
115*3f982cf4SFabien Sanglard 5 /* channels */,
116*3f982cf4SFabien Sanglard 32000 /* bit_rate */,
117*3f982cf4SFabien Sanglard 44000 /* sample_rate */,
118*3f982cf4SFabien Sanglard std::chrono::milliseconds(300),
119*3f982cf4SFabien Sanglard "mp4a.40.5"};
120*3f982cf4SFabien Sanglard
121*3f982cf4SFabien Sanglard const VideoCaptureConfig kVideoCaptureConfigMissingResolutions{
122*3f982cf4SFabien Sanglard VideoCodec::kHevc,
123*3f982cf4SFabien Sanglard {60, 1},
124*3f982cf4SFabien Sanglard 300000 /* max_bit_rate */,
125*3f982cf4SFabien Sanglard std::vector<Resolution>{},
126*3f982cf4SFabien Sanglard std::chrono::milliseconds(500),
127*3f982cf4SFabien Sanglard "hev1.1.6.L150.B0"};
128*3f982cf4SFabien Sanglard
129*3f982cf4SFabien Sanglard const VideoCaptureConfig kVideoCaptureConfigInvalid{
130*3f982cf4SFabien Sanglard VideoCodec::kHevc,
131*3f982cf4SFabien Sanglard {60, 1},
132*3f982cf4SFabien Sanglard -300000 /* max_bit_rate */,
133*3f982cf4SFabien Sanglard std::vector<Resolution>{Resolution{1920, 1080}, Resolution{1280, 720}}};
134*3f982cf4SFabien Sanglard
135*3f982cf4SFabien Sanglard const VideoCaptureConfig kVideoCaptureConfigValid{
136*3f982cf4SFabien Sanglard VideoCodec::kHevc,
137*3f982cf4SFabien Sanglard {60, 1},
138*3f982cf4SFabien Sanglard 300000 /* max_bit_rate */,
139*3f982cf4SFabien Sanglard std::vector<Resolution>{Resolution{1280, 720}, Resolution{1920, 1080}},
140*3f982cf4SFabien Sanglard std::chrono::milliseconds(250),
141*3f982cf4SFabien Sanglard "hev1.1.6.L150.B0"};
142*3f982cf4SFabien Sanglard
143*3f982cf4SFabien Sanglard const VideoCaptureConfig kVideoCaptureConfigValidSimplest{
144*3f982cf4SFabien Sanglard VideoCodec::kHevc,
145*3f982cf4SFabien Sanglard {60, 1},
146*3f982cf4SFabien Sanglard 300000 /* max_bit_rate */,
147*3f982cf4SFabien Sanglard std::vector<Resolution>{Resolution{1920, 1080}}};
148*3f982cf4SFabien Sanglard
149*3f982cf4SFabien Sanglard class FakeClient : public SenderSession::Client {
150*3f982cf4SFabien Sanglard public:
151*3f982cf4SFabien Sanglard MOCK_METHOD(void,
152*3f982cf4SFabien Sanglard OnNegotiated,
153*3f982cf4SFabien Sanglard (const SenderSession*,
154*3f982cf4SFabien Sanglard SenderSession::ConfiguredSenders,
155*3f982cf4SFabien Sanglard capture_recommendations::Recommendations),
156*3f982cf4SFabien Sanglard (override));
157*3f982cf4SFabien Sanglard MOCK_METHOD(void,
158*3f982cf4SFabien Sanglard OnRemotingNegotiated,
159*3f982cf4SFabien Sanglard (const SenderSession*, SenderSession::RemotingNegotiation),
160*3f982cf4SFabien Sanglard (override));
161*3f982cf4SFabien Sanglard MOCK_METHOD(void, OnError, (const SenderSession*, Error error), (override));
162*3f982cf4SFabien Sanglard };
163*3f982cf4SFabien Sanglard
164*3f982cf4SFabien Sanglard } // namespace
165*3f982cf4SFabien Sanglard
166*3f982cf4SFabien Sanglard class SenderSessionTest : public ::testing::Test {
167*3f982cf4SFabien Sanglard public:
SenderSessionTest()168*3f982cf4SFabien Sanglard SenderSessionTest() : clock_(Clock::time_point{}), task_runner_(&clock_) {}
169*3f982cf4SFabien Sanglard
MakeEnvironment()170*3f982cf4SFabien Sanglard std::unique_ptr<MockEnvironment> MakeEnvironment() {
171*3f982cf4SFabien Sanglard auto environment_ = std::make_unique<NiceMock<MockEnvironment>>(
172*3f982cf4SFabien Sanglard &FakeClock::now, &task_runner_);
173*3f982cf4SFabien Sanglard ON_CALL(*environment_, GetBoundLocalEndpoint())
174*3f982cf4SFabien Sanglard .WillByDefault(
175*3f982cf4SFabien Sanglard Return(IPEndpoint{IPAddress::Parse("127.0.0.1").value(), 12345}));
176*3f982cf4SFabien Sanglard return environment_;
177*3f982cf4SFabien Sanglard }
178*3f982cf4SFabien Sanglard
SetUp()179*3f982cf4SFabien Sanglard void SetUp() {
180*3f982cf4SFabien Sanglard message_port_ = std::make_unique<SimpleMessagePort>("receiver-12345");
181*3f982cf4SFabien Sanglard environment_ = MakeEnvironment();
182*3f982cf4SFabien Sanglard
183*3f982cf4SFabien Sanglard SenderSession::Configuration config{IPAddress::kV4LoopbackAddress(),
184*3f982cf4SFabien Sanglard &client_,
185*3f982cf4SFabien Sanglard environment_.get(),
186*3f982cf4SFabien Sanglard message_port_.get(),
187*3f982cf4SFabien Sanglard "sender-12345",
188*3f982cf4SFabien Sanglard "receiver-12345",
189*3f982cf4SFabien Sanglard /* use_android_rtp_hack */ true};
190*3f982cf4SFabien Sanglard session_ = std::make_unique<SenderSession>(std::move(config));
191*3f982cf4SFabien Sanglard }
192*3f982cf4SFabien Sanglard
NegotiateMirroringWithValidConfigs()193*3f982cf4SFabien Sanglard void NegotiateMirroringWithValidConfigs() {
194*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
195*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
196*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
197*3f982cf4SFabien Sanglard ASSERT_TRUE(error.ok());
198*3f982cf4SFabien Sanglard }
199*3f982cf4SFabien Sanglard
NegotiateRemotingWithValidConfigs()200*3f982cf4SFabien Sanglard void NegotiateRemotingWithValidConfigs() {
201*3f982cf4SFabien Sanglard const Error error = session_->NegotiateRemoting(kAudioCaptureConfigValid,
202*3f982cf4SFabien Sanglard kVideoCaptureConfigValid);
203*3f982cf4SFabien Sanglard ASSERT_TRUE(error.ok());
204*3f982cf4SFabien Sanglard }
205*3f982cf4SFabien Sanglard
206*3f982cf4SFabien Sanglard // Answers require specific fields from the original offer to be valid.
ConstructAnswerFromOffer(CastMode mode)207*3f982cf4SFabien Sanglard std::string ConstructAnswerFromOffer(CastMode mode) {
208*3f982cf4SFabien Sanglard const auto& messages = message_port_->posted_messages();
209*3f982cf4SFabien Sanglard if (messages.size() != 1) {
210*3f982cf4SFabien Sanglard return {};
211*3f982cf4SFabien Sanglard }
212*3f982cf4SFabien Sanglard auto message_body = json::Parse(messages[0]);
213*3f982cf4SFabien Sanglard if (message_body.is_error()) {
214*3f982cf4SFabien Sanglard return {};
215*3f982cf4SFabien Sanglard }
216*3f982cf4SFabien Sanglard const Json::Value offer = std::move(message_body.value());
217*3f982cf4SFabien Sanglard EXPECT_EQ("OFFER", offer["type"].asString());
218*3f982cf4SFabien Sanglard EXPECT_LT(0, offer["seqNum"].asInt());
219*3f982cf4SFabien Sanglard
220*3f982cf4SFabien Sanglard const Json::Value& offer_body = offer["offer"];
221*3f982cf4SFabien Sanglard if (!offer_body.isObject()) {
222*3f982cf4SFabien Sanglard return {};
223*3f982cf4SFabien Sanglard }
224*3f982cf4SFabien Sanglard
225*3f982cf4SFabien Sanglard const Json::Value& streams = offer_body["supportedStreams"];
226*3f982cf4SFabien Sanglard EXPECT_TRUE(streams.isArray());
227*3f982cf4SFabien Sanglard EXPECT_EQ(2u, streams.size());
228*3f982cf4SFabien Sanglard
229*3f982cf4SFabien Sanglard const Json::Value& audio_stream = streams[0];
230*3f982cf4SFabien Sanglard const int audio_index = audio_stream["index"].asInt();
231*3f982cf4SFabien Sanglard const int audio_ssrc = audio_stream["ssrc"].asUInt();
232*3f982cf4SFabien Sanglard
233*3f982cf4SFabien Sanglard const Json::Value& video_stream = streams[1];
234*3f982cf4SFabien Sanglard const int video_index = video_stream["index"].asInt();
235*3f982cf4SFabien Sanglard const int video_ssrc = video_stream["ssrc"].asUInt();
236*3f982cf4SFabien Sanglard
237*3f982cf4SFabien Sanglard constexpr char kAnswerTemplate[] = R"({
238*3f982cf4SFabien Sanglard "type": "ANSWER",
239*3f982cf4SFabien Sanglard "seqNum": %d,
240*3f982cf4SFabien Sanglard "result": "ok",
241*3f982cf4SFabien Sanglard "answer": {
242*3f982cf4SFabien Sanglard "castMode": "%s",
243*3f982cf4SFabien Sanglard "udpPort": 1234,
244*3f982cf4SFabien Sanglard "sendIndexes": [%d, %d],
245*3f982cf4SFabien Sanglard "ssrcs": [%d, %d]
246*3f982cf4SFabien Sanglard }
247*3f982cf4SFabien Sanglard })";
248*3f982cf4SFabien Sanglard return StringPrintf(kAnswerTemplate, offer["seqNum"].asInt(),
249*3f982cf4SFabien Sanglard mode == CastMode::kMirroring ? "mirroring" : "remoting",
250*3f982cf4SFabien Sanglard audio_index, video_index, audio_ssrc + 1,
251*3f982cf4SFabien Sanglard video_ssrc + 1);
252*3f982cf4SFabien Sanglard }
253*3f982cf4SFabien Sanglard
254*3f982cf4SFabien Sanglard protected:
255*3f982cf4SFabien Sanglard StrictMock<FakeClient> client_;
256*3f982cf4SFabien Sanglard FakeClock clock_;
257*3f982cf4SFabien Sanglard std::unique_ptr<MockEnvironment> environment_;
258*3f982cf4SFabien Sanglard std::unique_ptr<SimpleMessagePort> message_port_;
259*3f982cf4SFabien Sanglard std::unique_ptr<SenderSession> session_;
260*3f982cf4SFabien Sanglard FakeTaskRunner task_runner_;
261*3f982cf4SFabien Sanglard };
262*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfNoConfigsToOffer)263*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfNoConfigsToOffer) {
264*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(std::vector<AudioCaptureConfig>{},
265*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{});
266*3f982cf4SFabien Sanglard
267*3f982cf4SFabien Sanglard EXPECT_EQ(error,
268*3f982cf4SFabien Sanglard Error(Error::Code::kParameterInvalid,
269*3f982cf4SFabien Sanglard "Need at least one audio or video config to negotiate."));
270*3f982cf4SFabien Sanglard }
271*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfInvalidAudioCaptureConfig)272*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfInvalidAudioCaptureConfig) {
273*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
274*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigInvalidChannels},
275*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{});
276*3f982cf4SFabien Sanglard
277*3f982cf4SFabien Sanglard EXPECT_EQ(error,
278*3f982cf4SFabien Sanglard Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
279*3f982cf4SFabien Sanglard }
280*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfInvalidVideoCaptureConfig)281*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfInvalidVideoCaptureConfig) {
282*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
283*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{},
284*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigInvalid});
285*3f982cf4SFabien Sanglard EXPECT_EQ(error,
286*3f982cf4SFabien Sanglard Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
287*3f982cf4SFabien Sanglard }
288*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfMissingResolutions)289*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfMissingResolutions) {
290*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
291*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{},
292*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigMissingResolutions});
293*3f982cf4SFabien Sanglard EXPECT_EQ(error,
294*3f982cf4SFabien Sanglard Error(Error::Code::kParameterInvalid, "Invalid configs provided."));
295*3f982cf4SFabien Sanglard }
296*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,SendsOfferWithZeroBitrateOptions)297*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, SendsOfferWithZeroBitrateOptions) {
298*3f982cf4SFabien Sanglard VideoCaptureConfig video_config = kVideoCaptureConfigValid;
299*3f982cf4SFabien Sanglard video_config.max_bit_rate = 0;
300*3f982cf4SFabien Sanglard AudioCaptureConfig audio_config = kAudioCaptureConfigValid;
301*3f982cf4SFabien Sanglard audio_config.bit_rate = 0;
302*3f982cf4SFabien Sanglard
303*3f982cf4SFabien Sanglard const Error error =
304*3f982cf4SFabien Sanglard session_->Negotiate(std::vector<AudioCaptureConfig>{audio_config},
305*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{video_config});
306*3f982cf4SFabien Sanglard EXPECT_TRUE(error.ok());
307*3f982cf4SFabien Sanglard
308*3f982cf4SFabien Sanglard const auto& messages = message_port_->posted_messages();
309*3f982cf4SFabien Sanglard ASSERT_EQ(1u, messages.size());
310*3f982cf4SFabien Sanglard auto message_body = json::Parse(messages[0]);
311*3f982cf4SFabien Sanglard ASSERT_TRUE(message_body.is_value());
312*3f982cf4SFabien Sanglard const Json::Value offer = std::move(message_body.value());
313*3f982cf4SFabien Sanglard EXPECT_EQ("OFFER", offer["type"].asString());
314*3f982cf4SFabien Sanglard }
315*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,SendsOfferWithSimpleVideoOnly)316*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, SendsOfferWithSimpleVideoOnly) {
317*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
318*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{},
319*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
320*3f982cf4SFabien Sanglard EXPECT_TRUE(error.ok());
321*3f982cf4SFabien Sanglard
322*3f982cf4SFabien Sanglard const auto& messages = message_port_->posted_messages();
323*3f982cf4SFabien Sanglard ASSERT_EQ(1u, messages.size());
324*3f982cf4SFabien Sanglard auto message_body = json::Parse(messages[0]);
325*3f982cf4SFabien Sanglard ASSERT_TRUE(message_body.is_value());
326*3f982cf4SFabien Sanglard const Json::Value offer = std::move(message_body.value());
327*3f982cf4SFabien Sanglard EXPECT_EQ("OFFER", offer["type"].asString());
328*3f982cf4SFabien Sanglard }
329*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,SendsOfferAudioOnly)330*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, SendsOfferAudioOnly) {
331*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
332*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
333*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{});
334*3f982cf4SFabien Sanglard EXPECT_TRUE(error.ok());
335*3f982cf4SFabien Sanglard
336*3f982cf4SFabien Sanglard const auto& messages = message_port_->posted_messages();
337*3f982cf4SFabien Sanglard ASSERT_EQ(1u, messages.size());
338*3f982cf4SFabien Sanglard auto message_body = json::Parse(messages[0]);
339*3f982cf4SFabien Sanglard ASSERT_TRUE(message_body.is_value());
340*3f982cf4SFabien Sanglard const Json::Value offer = std::move(message_body.value());
341*3f982cf4SFabien Sanglard EXPECT_EQ("OFFER", offer["type"].asString());
342*3f982cf4SFabien Sanglard }
343*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,SendsOfferMessage)344*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, SendsOfferMessage) {
345*3f982cf4SFabien Sanglard session_->Negotiate(
346*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
347*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
348*3f982cf4SFabien Sanglard
349*3f982cf4SFabien Sanglard const auto& messages = message_port_->posted_messages();
350*3f982cf4SFabien Sanglard ASSERT_EQ(1u, messages.size());
351*3f982cf4SFabien Sanglard
352*3f982cf4SFabien Sanglard auto message_body = json::Parse(messages[0]);
353*3f982cf4SFabien Sanglard ASSERT_TRUE(message_body.is_value());
354*3f982cf4SFabien Sanglard const Json::Value offer = std::move(message_body.value());
355*3f982cf4SFabien Sanglard EXPECT_EQ("OFFER", offer["type"].asString());
356*3f982cf4SFabien Sanglard EXPECT_LT(0, offer["seqNum"].asInt());
357*3f982cf4SFabien Sanglard
358*3f982cf4SFabien Sanglard const Json::Value& offer_body = offer["offer"];
359*3f982cf4SFabien Sanglard ASSERT_FALSE(offer_body.isNull());
360*3f982cf4SFabien Sanglard ASSERT_TRUE(offer_body.isObject());
361*3f982cf4SFabien Sanglard EXPECT_EQ("mirroring", offer_body["castMode"].asString());
362*3f982cf4SFabien Sanglard
363*3f982cf4SFabien Sanglard const Json::Value& streams = offer_body["supportedStreams"];
364*3f982cf4SFabien Sanglard EXPECT_TRUE(streams.isArray());
365*3f982cf4SFabien Sanglard EXPECT_EQ(2u, streams.size());
366*3f982cf4SFabien Sanglard
367*3f982cf4SFabien Sanglard const Json::Value& audio_stream = streams[0];
368*3f982cf4SFabien Sanglard EXPECT_EQ("aac", audio_stream["codecName"].asString());
369*3f982cf4SFabien Sanglard EXPECT_EQ(0, audio_stream["index"].asInt());
370*3f982cf4SFabien Sanglard EXPECT_EQ(32u, audio_stream["aesKey"].asString().length());
371*3f982cf4SFabien Sanglard EXPECT_EQ(32u, audio_stream["aesIvMask"].asString().length());
372*3f982cf4SFabien Sanglard EXPECT_EQ(5, audio_stream["channels"].asInt());
373*3f982cf4SFabien Sanglard EXPECT_LT(0u, audio_stream["ssrc"].asUInt());
374*3f982cf4SFabien Sanglard EXPECT_EQ(127, audio_stream["rtpPayloadType"].asInt());
375*3f982cf4SFabien Sanglard EXPECT_EQ("mp4a.40.5", audio_stream["codecParameter"].asString());
376*3f982cf4SFabien Sanglard
377*3f982cf4SFabien Sanglard const Json::Value& video_stream = streams[1];
378*3f982cf4SFabien Sanglard EXPECT_EQ("hevc", video_stream["codecName"].asString());
379*3f982cf4SFabien Sanglard EXPECT_EQ(1, video_stream["index"].asInt());
380*3f982cf4SFabien Sanglard EXPECT_EQ(32u, video_stream["aesKey"].asString().length());
381*3f982cf4SFabien Sanglard EXPECT_EQ(32u, video_stream["aesIvMask"].asString().length());
382*3f982cf4SFabien Sanglard EXPECT_EQ(1, video_stream["channels"].asInt());
383*3f982cf4SFabien Sanglard EXPECT_LT(0u, video_stream["ssrc"].asUInt());
384*3f982cf4SFabien Sanglard EXPECT_EQ(96, video_stream["rtpPayloadType"].asInt());
385*3f982cf4SFabien Sanglard EXPECT_EQ("hev1.1.6.L150.B0", video_stream["codecParameter"].asString());
386*3f982cf4SFabien Sanglard }
387*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesValidAnswer)388*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesValidAnswer) {
389*3f982cf4SFabien Sanglard NegotiateMirroringWithValidConfigs();
390*3f982cf4SFabien Sanglard std::string answer = ConstructAnswerFromOffer(CastMode::kMirroring);
391*3f982cf4SFabien Sanglard
392*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnNegotiated(session_.get(), _, _));
393*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(answer);
394*3f982cf4SFabien Sanglard }
395*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesInvalidNamespace)396*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesInvalidNamespace) {
397*3f982cf4SFabien Sanglard NegotiateMirroringWithValidConfigs();
398*3f982cf4SFabien Sanglard std::string answer = ConstructAnswerFromOffer(CastMode::kMirroring);
399*3f982cf4SFabien Sanglard message_port_->ReceiveMessage("random-namespace", answer);
400*3f982cf4SFabien Sanglard }
401*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesMalformedAnswer)402*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesMalformedAnswer) {
403*3f982cf4SFabien Sanglard session_->Negotiate(
404*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
405*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
406*3f982cf4SFabien Sanglard
407*3f982cf4SFabien Sanglard // Note that unlike when we simply don't select any streams, when the answer
408*3f982cf4SFabien Sanglard // is actually malformed we have no way of knowing it was an answer at all,
409*3f982cf4SFabien Sanglard // so we report an Error and drop the message.
410*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
411*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kMalformedAnswerMessage);
412*3f982cf4SFabien Sanglard }
413*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesImproperlyFormattedAnswer)414*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesImproperlyFormattedAnswer) {
415*3f982cf4SFabien Sanglard session_->Negotiate(
416*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
417*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
418*3f982cf4SFabien Sanglard
419*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
420*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kValidJsonInvalidFormatAnswerMessage);
421*3f982cf4SFabien Sanglard }
422*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesInvalidAnswer)423*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesInvalidAnswer) {
424*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
425*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
426*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
427*3f982cf4SFabien Sanglard
428*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
429*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kValidJsonInvalidAnswerMessage);
430*3f982cf4SFabien Sanglard }
431*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesNullAnswer)432*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesNullAnswer) {
433*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
434*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
435*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
436*3f982cf4SFabien Sanglard
437*3f982cf4SFabien Sanglard EXPECT_TRUE(error.ok());
438*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
439*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kMissingAnswerMessage);
440*3f982cf4SFabien Sanglard }
441*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesInvalidSequenceNumber)442*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesInvalidSequenceNumber) {
443*3f982cf4SFabien Sanglard const Error error = session_->Negotiate(
444*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
445*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
446*3f982cf4SFabien Sanglard
447*3f982cf4SFabien Sanglard // We should just discard messages with an invalid sequence number.
448*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kInvalidSequenceNumberMessage);
449*3f982cf4SFabien Sanglard }
450*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesUnknownTypeMessageWithValidSeqNum)451*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesUnknownTypeMessageWithValidSeqNum) {
452*3f982cf4SFabien Sanglard session_->Negotiate(
453*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
454*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
455*3f982cf4SFabien Sanglard
456*3f982cf4SFabien Sanglard // If a message is of unknown type but has an expected seqnum, it's
457*3f982cf4SFabien Sanglard // probably a malformed response.
458*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
459*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kUnknownTypeMessage);
460*3f982cf4SFabien Sanglard }
461*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesInvalidTypeMessageWithValidSeqNum)462*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesInvalidTypeMessageWithValidSeqNum) {
463*3f982cf4SFabien Sanglard session_->Negotiate(
464*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
465*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
466*3f982cf4SFabien Sanglard
467*3f982cf4SFabien Sanglard // If a message is of unknown type but has an expected seqnum, it's
468*3f982cf4SFabien Sanglard // probably a malformed response.
469*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
470*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kInvalidTypeMessage);
471*3f982cf4SFabien Sanglard }
472*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesInvalidTypeMessage)473*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesInvalidTypeMessage) {
474*3f982cf4SFabien Sanglard session_->Negotiate(
475*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
476*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
477*3f982cf4SFabien Sanglard
478*3f982cf4SFabien Sanglard // We should just discard messages with an invalid message type and
479*3f982cf4SFabien Sanglard // no sequence number.
480*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kInvalidTypeMessageWithNoSeqNum);
481*3f982cf4SFabien Sanglard }
482*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesErrorMessage)483*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesErrorMessage) {
484*3f982cf4SFabien Sanglard session_->Negotiate(
485*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
486*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
487*3f982cf4SFabien Sanglard
488*3f982cf4SFabien Sanglard // We should report error answers.
489*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnError(session_.get(), _));
490*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kErrorAnswerMessage);
491*3f982cf4SFabien Sanglard }
492*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,DoesNotCrashOnMessagePortError)493*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, DoesNotCrashOnMessagePortError) {
494*3f982cf4SFabien Sanglard session_->Negotiate(
495*3f982cf4SFabien Sanglard std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
496*3f982cf4SFabien Sanglard std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
497*3f982cf4SFabien Sanglard
498*3f982cf4SFabien Sanglard message_port_->ReceiveError(Error(Error::Code::kUnknownError));
499*3f982cf4SFabien Sanglard }
500*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ReportsZeroBandwidthWhenNoPacketsSent)501*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ReportsZeroBandwidthWhenNoPacketsSent) {
502*3f982cf4SFabien Sanglard // TODO(issuetracker.google.com/183996645): As part of end to end testing,
503*3f982cf4SFabien Sanglard // we need to ensure that we are providing reasonable network bandwidth
504*3f982cf4SFabien Sanglard // measurements.
505*3f982cf4SFabien Sanglard EXPECT_EQ(0, session_->GetEstimatedNetworkBandwidth());
506*3f982cf4SFabien Sanglard }
507*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfInvalidAudioCaptureConfigRemoting)508*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfInvalidAudioCaptureConfigRemoting) {
509*3f982cf4SFabien Sanglard const Error error = session_->NegotiateRemoting(
510*3f982cf4SFabien Sanglard kAudioCaptureConfigInvalidChannels, kVideoCaptureConfigValid);
511*3f982cf4SFabien Sanglard
512*3f982cf4SFabien Sanglard EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
513*3f982cf4SFabien Sanglard }
514*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfInvalidVideoCaptureConfigRemoting)515*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfInvalidVideoCaptureConfigRemoting) {
516*3f982cf4SFabien Sanglard const Error error = session_->NegotiateRemoting(kAudioCaptureConfigValid,
517*3f982cf4SFabien Sanglard kVideoCaptureConfigInvalid);
518*3f982cf4SFabien Sanglard EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
519*3f982cf4SFabien Sanglard }
520*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,ComplainsIfMissingResolutionsRemoting)521*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, ComplainsIfMissingResolutionsRemoting) {
522*3f982cf4SFabien Sanglard const Error error = session_->NegotiateRemoting(
523*3f982cf4SFabien Sanglard kAudioCaptureConfigValid, kVideoCaptureConfigMissingResolutions);
524*3f982cf4SFabien Sanglard EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
525*3f982cf4SFabien Sanglard }
526*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,HandlesValidAnswerRemoting)527*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, HandlesValidAnswerRemoting) {
528*3f982cf4SFabien Sanglard NegotiateRemotingWithValidConfigs();
529*3f982cf4SFabien Sanglard std::string answer = ConstructAnswerFromOffer(CastMode::kRemoting);
530*3f982cf4SFabien Sanglard
531*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _));
532*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(answer);
533*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kCapabilitiesResponse);
534*3f982cf4SFabien Sanglard }
535*3f982cf4SFabien Sanglard
TEST_F(SenderSessionTest,SuccessfulRemotingNegotiationYieldsValidObject)536*3f982cf4SFabien Sanglard TEST_F(SenderSessionTest, SuccessfulRemotingNegotiationYieldsValidObject) {
537*3f982cf4SFabien Sanglard NegotiateRemotingWithValidConfigs();
538*3f982cf4SFabien Sanglard std::string answer = ConstructAnswerFromOffer(CastMode::kRemoting);
539*3f982cf4SFabien Sanglard
540*3f982cf4SFabien Sanglard SenderSession::RemotingNegotiation negotiation;
541*3f982cf4SFabien Sanglard EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _))
542*3f982cf4SFabien Sanglard .WillOnce(testing::SaveArg<1>(&negotiation));
543*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(answer);
544*3f982cf4SFabien Sanglard message_port_->ReceiveMessage(kCapabilitiesResponse);
545*3f982cf4SFabien Sanglard
546*3f982cf4SFabien Sanglard // The capabilities should match the values in |kCapabilitiesResponse|.
547*3f982cf4SFabien Sanglard EXPECT_THAT(negotiation.capabilities.audio,
548*3f982cf4SFabien Sanglard testing::ElementsAre(AudioCapability::kBaselineSet,
549*3f982cf4SFabien Sanglard AudioCapability::kAac));
550*3f982cf4SFabien Sanglard
551*3f982cf4SFabien Sanglard // The "video" capability is ignored since it means nothing.
552*3f982cf4SFabien Sanglard EXPECT_THAT(negotiation.capabilities.video,
553*3f982cf4SFabien Sanglard testing::ElementsAre(VideoCapability::kVp8));
554*3f982cf4SFabien Sanglard
555*3f982cf4SFabien Sanglard // The messenger is tested elsewhere, but we can sanity check that we got a valid
556*3f982cf4SFabien Sanglard // one here.
557*3f982cf4SFabien Sanglard EXPECT_TRUE(session_->rpc_messenger());
558*3f982cf4SFabien Sanglard const RpcMessenger::Handle handle =
559*3f982cf4SFabien Sanglard session_->rpc_messenger()->GetUniqueHandle();
560*3f982cf4SFabien Sanglard EXPECT_NE(RpcMessenger::kInvalidHandle, handle);
561*3f982cf4SFabien Sanglard }
562*3f982cf4SFabien Sanglard
563*3f982cf4SFabien Sanglard } // namespace cast
564*3f982cf4SFabien Sanglard } // namespace openscreen
565