Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
|
joedow
2016/04/28 22:53:54
no copyright in the header for new files.
Hzj_jie
2016/05/03 19:07:05
Done.
| |
| 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 <cassert> | |
| 6 #include <iostream> | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/at_exit.h" | |
| 12 #include "base/atomicops.h" | |
| 13 #include "base/bind.h" | |
| 14 #include "base/command_line.h" | |
| 15 #include "base/location.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/memory/ptr_util.h" | |
| 18 #include "base/memory/ref_counted.h" | |
| 19 #include "base/message_loop/message_loop.h" | |
| 20 #include "base/run_loop.h" | |
| 21 #include "base/threading/platform_thread.h" | |
| 22 #include "base/time/time.h" | |
| 23 #include "remoting/base/auto_thread_task_runner.h" | |
| 24 #include "remoting/codec/video_encoder_verbatim.h" | |
| 25 #include "remoting/codec/video_encoder_vpx.h" | |
| 26 #include "remoting/host/chromoting_host.h" | |
| 27 #include "remoting/host/chromoting_host_context.h" | |
| 28 #include "remoting/host/client_session.h" | |
| 29 #include "remoting/host/host_extension.h" | |
| 30 #include "remoting/host/host_mock_objects.h" | |
| 31 #include "remoting/host/it2me_desktop_environment.h" | |
| 32 #include "remoting/host/resources.h" | |
| 33 #include "remoting/proto/audio.pb.h" | |
| 34 #include "remoting/protocol/audio_stub.h" | |
| 35 #include "remoting/protocol/fake_connection_to_client.h" | |
| 36 #include "remoting/protocol/pairing_registry.h" | |
| 37 #include "remoting/protocol/protocol_mock_objects.h" | |
| 38 #include "remoting/protocol/session_config.h" | |
| 39 #include "remoting/protocol/video_frame_pump.h" | |
| 40 #include "remoting/protocol/video_stub.h" | |
| 41 | |
| 42 #if defined(OS_LINUX) | |
| 43 #include <gtk/gtk.h> | |
| 44 #include <X11/Xlib.h> | |
| 45 | |
| 46 #include "base/linux_util.h" | |
| 47 #endif // defined(OS_LINUX) | |
| 48 | |
| 49 using base::AtExitManager; | |
| 50 using base::Bind; | |
| 51 using base::Closure; | |
| 52 using base::CommandLine; | |
| 53 using base::MessageLoopForUI; | |
| 54 using base::RunLoop; | |
| 55 using base::TimeDelta; | |
| 56 using base::WrapUnique; | |
| 57 using google::protobuf::MessageLite; | |
| 58 using remoting::AudioPacket; | |
| 59 using remoting::ChromotingHostContext; | |
| 60 using remoting::ClientSession; | |
| 61 using remoting::HostExtension; | |
| 62 using remoting::MockClientSessionEventHandler; | |
| 63 using remoting::It2MeDesktopEnvironmentFactory; | |
| 64 using remoting::VideoAck; | |
| 65 using remoting::VideoEncoder; | |
| 66 using remoting::VideoEncoderVpx; | |
| 67 using remoting::VideoEncoderVerbatim; | |
| 68 using remoting::VideoPacket; | |
| 69 using remoting::protocol::AudioControl; | |
| 70 using remoting::protocol::AudioStub; | |
| 71 using remoting::protocol::Capabilities; | |
| 72 using remoting::protocol::ChannelConfig; | |
| 73 using remoting::protocol::ClientResolution; | |
| 74 using remoting::protocol::ClientStub; | |
| 75 using remoting::protocol::ClipboardEvent; | |
| 76 using remoting::protocol::ConnectionToClient; | |
| 77 using remoting::protocol::CursorShapeInfo; | |
| 78 using remoting::protocol::ExtensionMessage; | |
| 79 using remoting::protocol::FakeConnectionToClient; | |
| 80 using remoting::protocol::HostStub; | |
| 81 using remoting::protocol::MockClientStub; | |
| 82 using remoting::protocol::MockHostStub; | |
| 83 using remoting::protocol::MockSession; | |
| 84 using remoting::protocol::PairingRegistry; | |
| 85 using remoting::protocol::PairingRequest; | |
| 86 using remoting::protocol::PairingResponse; | |
| 87 using remoting::protocol::SessionConfig; | |
| 88 using remoting::protocol::VideoControl; | |
| 89 using remoting::protocol::VideoFeedbackStub; | |
| 90 using remoting::protocol::VideoFramePump; | |
| 91 using remoting::protocol::VideoLayout; | |
| 92 using remoting::protocol::VideoStream; | |
| 93 using remoting::protocol::VideoStub; | |
| 94 using std::cout; | |
| 95 using std::endl; | |
| 96 using std::move; | |
| 97 using std::string; | |
| 98 using std::vector; | |
| 99 using std::unique_ptr; | |
| 100 using testing::ReturnRef; | |
| 101 using webrtc::DesktopCapturer; | |
|
joedow
2016/04/28 22:53:55
In general we don't use using statements like this
Hzj_jie
2016/05/03 19:07:05
Yes, I should remove most of them before sending o
| |
| 102 | |
| 103 namespace { | |
| 104 | |
| 105 const bool g_output_to_stdout = false; | |
| 106 | |
| 107 template <typename T> | |
| 108 class NoBarrierAtomic { | |
| 109 public: | |
| 110 T operator++() { | |
| 111 return base::subtle::NoBarrier_AtomicIncrement(&i, 1) - 1; | |
| 112 } | |
| 113 | |
| 114 T operator++(int) { | |
| 115 return base::subtle::NoBarrier_AtomicIncrement(&i, 1); | |
| 116 } | |
| 117 | |
| 118 T operator--() { | |
| 119 return base::subtle::NoBarrier_AtomicIncrement(&i, -1) - 1; | |
| 120 } | |
| 121 | |
| 122 T operator--(int) { | |
| 123 return base::subtle::NoBarrier_AtomicIncrement(&i, -1); | |
| 124 } | |
| 125 | |
| 126 T operator+=(T other) { | |
| 127 return base::subtle::NoBarrier_AtomicIncrement(&i, other); | |
| 128 } | |
| 129 | |
| 130 T operator-=(T other) { | |
| 131 return base::subtle::NoBarrier_AtomicIncrement(&i, -other); | |
| 132 } | |
| 133 | |
| 134 T operator*() const { | |
| 135 return base::subtle::NoBarrier_Load(&i); | |
| 136 } | |
| 137 | |
| 138 private: | |
| 139 volatile T i; | |
| 140 }; | |
| 141 | |
| 142 class NoBarrierAtomicInt32 : public NoBarrierAtomic<base::subtle::Atomic32> {}; | |
| 143 #if ARCH_CPU_64_BITS | |
| 144 class NoBarrierAtomicInt64 : public NoBarrierAtomic<base::subtle::Atomic64> {}; | |
| 145 #else | |
| 146 | |
| 147 #include "base/synchronization/lock.h" | |
| 148 using base::AutoLock; | |
| 149 using base::Lock; | |
| 150 | |
| 151 // A barriered, lock based implementation | |
| 152 class NoBarrierAtomicInt64 { | |
| 153 public: | |
| 154 int64_t operator++() { | |
| 155 AutoLock l(lock); | |
| 156 return i++; | |
| 157 } | |
| 158 | |
| 159 int64_t operator++(int) { | |
| 160 AutoLock l(lock); | |
| 161 return ++i; | |
| 162 } | |
| 163 | |
| 164 int64_t operator--() { | |
| 165 AutoLock l(lock); | |
| 166 return i--; | |
| 167 } | |
| 168 | |
| 169 int64_t operator--(int) { | |
| 170 AutoLock l(lock); | |
| 171 return --i; | |
| 172 } | |
| 173 | |
| 174 int64_t operator+=(int64_t other) { | |
| 175 AutoLock l(lock); | |
| 176 return (i += other); | |
| 177 } | |
| 178 | |
| 179 int64_t operator-=(int64_t other) { | |
| 180 AutoLock l(lock); | |
| 181 return (i -= other); | |
| 182 } | |
| 183 | |
| 184 int64_t operator*() const { | |
| 185 base::subtle::MemoryBarrier(); | |
| 186 return i; | |
| 187 } | |
| 188 | |
| 189 private: | |
| 190 volatile int64_t i; | |
| 191 Lock lock; | |
| 192 }; | |
| 193 #endif | |
| 194 | |
| 195 class MessageLogger { | |
|
joedow
2016/04/28 22:53:55
Why aren't you using the standard logging infra we
Hzj_jie
2016/05/03 19:07:05
Renamed to MessageCounter, sorry for the confusion
| |
| 196 public: | |
| 197 MessageLogger() | |
| 198 : count_(), | |
| 199 size_(), | |
| 200 last_size_(), | |
| 201 started_(base::Time::Now()) {} | |
| 202 | |
| 203 int message_count() const { | |
| 204 return *count_; | |
| 205 } | |
| 206 | |
| 207 int64_t message_size() const { | |
| 208 return *size_; | |
| 209 } | |
| 210 | |
| 211 int last_message_size() const { | |
| 212 return last_size_; | |
| 213 } | |
| 214 | |
| 215 double DurationSeconds() const { | |
| 216 return (base::Time::Now() - started_).InSecondsF(); | |
| 217 } | |
| 218 | |
| 219 protected: | |
| 220 void LogMessage(const MessageLite& message) { | |
| 221 count_++; | |
| 222 last_size_ = message.ByteSize(); | |
| 223 size_ += last_size_; | |
| 224 } | |
| 225 | |
| 226 private: | |
| 227 NoBarrierAtomicInt32 count_; | |
| 228 NoBarrierAtomicInt64 size_; | |
| 229 int last_size_; | |
| 230 base::Time started_; | |
| 231 }; | |
| 232 | |
| 233 class LogClientStub : public ClientStub, public MessageLogger { | |
| 234 public: | |
| 235 void SetCapabilities(const Capabilities& capabilities) override {} | |
| 236 void SetPairingResponse(const PairingResponse& response) override {} | |
| 237 void InjectClipboardEvent(const ClipboardEvent& event) override {} | |
| 238 void SetCursorShape(const CursorShapeInfo& cursor_shape) override {} | |
| 239 | |
| 240 void DeliverHostMessage(const ExtensionMessage& message) override { | |
| 241 if (g_output_to_stdout) { | |
| 242 cout << "DeliverHostMessage(" << message.ByteSize() << ")" << endl; | |
|
joedow
2016/04/28 22:53:54
I don't think cout is right, we should use the sam
Hzj_jie
2016/05/03 19:07:05
These cout(s) have been removed, they were for a q
| |
| 243 } | |
| 244 LogMessage(message); | |
| 245 } | |
| 246 | |
| 247 void SetVideoLayout(const VideoLayout& video_layout) override {} | |
| 248 }; | |
| 249 | |
| 250 class LogHostStub : public HostStub, public MessageLogger { | |
| 251 public: | |
| 252 void NotifyClientResolution(const ClientResolution& resolution) override {} | |
| 253 void ControlVideo(const VideoControl& video_control) override {} | |
| 254 void ControlAudio(const AudioControl& audio_control) override {} | |
| 255 void SetCapabilities(const Capabilities& capabilities) override {} | |
| 256 void RequestPairing(const PairingRequest& pairing_request) override {} | |
| 257 | |
| 258 void DeliverClientMessage(const ExtensionMessage& message) override { | |
| 259 if (g_output_to_stdout) { | |
| 260 cout << "DeliverClientMessage(" << message.ByteSize() << ")" << endl; | |
| 261 } | |
| 262 LogMessage(message); | |
| 263 } | |
| 264 }; | |
| 265 | |
| 266 class LogAudioStub : public AudioStub, public MessageLogger { | |
| 267 public: | |
| 268 void ProcessAudioPacket(unique_ptr<AudioPacket> audio_packet, | |
| 269 const Closure& done) override { | |
| 270 if (audio_packet) { | |
| 271 if (g_output_to_stdout) { | |
| 272 cout << "ProcessAudioPacket(" << audio_packet->data_size(); | |
| 273 for (int i = 0; i < audio_packet->data_size(); i++) { | |
| 274 cout << " - " << audio_packet->data(i).size(); | |
| 275 } | |
| 276 cout << ")" << endl; | |
| 277 } | |
| 278 LogMessage(*audio_packet); | |
| 279 } | |
| 280 done.Run(); | |
| 281 } | |
| 282 }; | |
| 283 | |
| 284 class LogVideoStub : public VideoStub, public MessageLogger { | |
| 285 public: | |
| 286 LogVideoStub(FakeConnectionToClient* connection) : connection_(connection) {} | |
| 287 | |
| 288 void ProcessVideoPacket(unique_ptr<VideoPacket> video_packet, | |
| 289 const Closure& done) override { | |
| 290 if (video_packet) { | |
| 291 if (g_output_to_stdout) { | |
| 292 cout << "ProcessVideoPacket(" | |
| 293 << video_packet->data().size() | |
| 294 << ")" | |
| 295 << endl; | |
| 296 } | |
| 297 if (connection_ && connection_->video_feedback_stub()) { | |
| 298 VideoAck* ack = new VideoAck(); | |
| 299 ack->set_frame_id(video_packet->frame_id()); | |
| 300 connection_->video_feedback_stub()->ProcessVideoAck(WrapUnique(ack)); | |
| 301 } | |
| 302 LogMessage(*video_packet); | |
| 303 } | |
| 304 done.Run(); | |
| 305 } | |
| 306 | |
| 307 private: | |
| 308 FakeConnectionToClient* connection_ = nullptr; | |
| 309 }; | |
| 310 | |
| 311 // Stores all objects a host needs | |
| 312 struct Container { | |
|
joedow
2016/04/28 22:53:55
I wonder if this should be a class and go into it'
Hzj_jie
2016/05/03 19:07:05
Done.
| |
| 313 MessageLoopForUI message_loop; | |
| 314 RunLoop run_loop; | |
| 315 unique_ptr<ChromotingHostContext> context; | |
| 316 It2MeDesktopEnvironmentFactory factory; | |
| 317 FakeConnectionToClient connection; | |
| 318 string session_jid; | |
| 319 unique_ptr<SessionConfig> config; | |
| 320 LogAudioStub audio_stub; | |
| 321 LogVideoStub video_stub; | |
| 322 LogClientStub client_stub; | |
| 323 LogHostStub host_stub; | |
| 324 MockClientSessionEventHandler handler; | |
| 325 unique_ptr<ClientSession> session; | |
| 326 | |
| 327 Container() | |
| 328 : message_loop(), | |
| 329 run_loop(), | |
| 330 context(ChromotingHostContext::Create( | |
| 331 new remoting::AutoThreadTaskRunner( | |
| 332 message_loop.task_runner(), run_loop.QuitClosure()))), | |
| 333 factory(context->network_task_runner(), | |
| 334 context->video_capture_task_runner(), | |
| 335 context->input_task_runner(), | |
| 336 context->ui_task_runner()), | |
| 337 connection(WrapUnique(new MockSession())), | |
| 338 session_jid("user@domain/rest-of-jid"), | |
| 339 #if defined(OS_LINUX) | |
| 340 config(SessionConfig::ForTest()), // Need a pipe name for linux | |
|
joedow
2016/04/28 22:53:55
This comment is confusing to me, is a pipe name sp
Hzj_jie
2016/05/03 19:07:05
Updated. We cannot support audio capture in Linux
| |
| 341 #else | |
| 342 config(SessionConfig::ForTestWithAudio()), | |
| 343 #endif | |
| 344 audio_stub(), | |
| 345 video_stub(&connection), | |
| 346 client_stub(), | |
| 347 host_stub(), | |
| 348 handler(), | |
| 349 session() { | |
| 350 EXPECT_CALL(*static_cast<MockSession*>(connection.session()), jid()) | |
|
joedow
2016/04/28 22:53:55
Did you pull in the GMOCK header? I didn't see it
Hzj_jie
2016/05/03 19:07:05
Great, thank you for the hint.
| |
| 351 .WillRepeatedly(ReturnRef(session_jid)); | |
| 352 EXPECT_CALL(*static_cast<MockSession*>(connection.session()), config()) | |
| 353 .WillRepeatedly(ReturnRef(*config)); | |
| 354 connection.set_audio_stub(&audio_stub); | |
| 355 connection.set_video_stub(&video_stub); | |
| 356 connection.set_client_stub(&client_stub); | |
| 357 connection.set_host_stub(&host_stub); | |
| 358 connection.set_video_encode_task_runner( | |
| 359 context->video_encode_task_runner()); | |
| 360 } | |
| 361 | |
| 362 void CreateClientSession() { | |
| 363 // Must run in network_task_runner | |
|
joedow
2016/04/28 22:53:55
You should DCHECK this to prevent it.
Hzj_jie
2016/05/03 19:07:05
No, ClientSession::OnConnectionAuthenticated and o
| |
| 364 session.reset(new ClientSession( | |
| 365 &handler, | |
| 366 context->audio_task_runner(), | |
| 367 unique_ptr<ConnectionToClient>(&connection), | |
| 368 &factory, | |
| 369 TimeDelta(), | |
| 370 scoped_refptr<PairingRegistry>(), | |
| 371 vector<HostExtension*>())); | |
| 372 } | |
| 373 }; | |
| 374 | |
| 375 void Execute(Container* container) { | |
| 376 container->CreateClientSession(); | |
| 377 container->session->OnConnectionAuthenticated(&container->connection); | |
| 378 container->session->OnConnectionChannelsConnected(&container->connection); | |
| 379 container->session->CreateVideoStreams(&container->connection); | |
| 380 } | |
| 381 | |
| 382 void BindAnalysisResultOutputter(Container* container); | |
| 383 | |
| 384 void OutputLogger(const char* name, const MessageLogger& logger) { | |
| 385 cout << name | |
| 386 << ": " | |
| 387 << logger.message_size() | |
| 388 << " bytes in " | |
| 389 << logger.message_count() | |
| 390 << " packages, last package " | |
| 391 << logger.last_message_size() | |
| 392 << " bytes, " | |
| 393 << static_cast<double>(logger.message_size()) / logger.message_count() | |
| 394 << " bytes/package, " | |
| 395 << static_cast<double>(logger.message_count()) / logger.DurationSeconds() | |
| 396 << " packages/sec, " | |
| 397 << static_cast<double>(logger.message_size()) / logger.DurationSeconds() | |
| 398 << " bytes/sec" | |
| 399 << endl; | |
| 400 } | |
| 401 | |
| 402 void OutputAnalysisResult(Container* container) { | |
| 403 OutputLogger("audio", container->audio_stub); | |
| 404 OutputLogger("video", container->video_stub); | |
| 405 OutputLogger("client", container->client_stub); | |
| 406 OutputLogger("host", container->host_stub); | |
| 407 BindAnalysisResultOutputter(container); | |
| 408 } | |
| 409 | |
| 410 void BindAnalysisResultOutputter(Container* container) { | |
| 411 container->context->ui_task_runner()->PostDelayedTask( | |
| 412 FROM_HERE, | |
| 413 Bind(&OutputAnalysisResult, container), | |
| 414 TimeDelta::FromSeconds(1)); | |
| 415 } | |
| 416 | |
| 417 } // namespace | |
| 418 | |
| 419 int main(int argc, const char** argv) { | |
| 420 AtExitManager at_exit_manager; | |
| 421 CommandLine::Init(argc, argv); | |
| 422 CommandLine::ForCurrentProcess()->AppendSwitch("disable-it2me-ui"); | |
|
joedow
2016/04/28 22:53:55
This feels odd unless there is a use case where we
Hzj_jie
2016/05/03 19:07:05
Yes, removed.
| |
| 423 Container container; | |
| 424 | |
| 425 #if defined(OS_LINUX) | |
| 426 // Required in order for us to run multiple X11 threads. | |
| 427 XInitThreads(); | |
| 428 | |
| 429 // Required for any calls into GTK functions, such as the Disconnect and | |
| 430 // Continue windows. Calling with nullptr arguments because we don't have | |
| 431 // any command line arguments for gtk to consume. | |
| 432 gtk_init(nullptr, nullptr); | |
| 433 | |
| 434 // Need to prime the host OS version value for linux to prevent IO on the | |
| 435 // network thread. base::GetLinuxDistro() caches the result. | |
| 436 base::GetLinuxDistro(); | |
| 437 #endif // OS_LINUX | |
| 438 | |
| 439 assert(remoting::LoadResources("en-US")); | |
|
joedow
2016/04/28 22:53:55
Why aren't we using chromium asserts here?
Hzj_jie
2016/05/03 19:07:05
Done.
| |
| 440 container.context->network_task_runner()->PostTask( | |
| 441 FROM_HERE, | |
| 442 Bind(&Execute, &container)); | |
| 443 BindAnalysisResultOutputter(&container); | |
| 444 container.run_loop.Run(); | |
| 445 } | |
| OLD | NEW |