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 |