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