Index: remoting/test/dummy_host.cc |
diff --git a/remoting/test/dummy_host.cc b/remoting/test/dummy_host.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d34156651947b3a556c0cea433e4a6cf0fd9051b |
--- /dev/null |
+++ b/remoting/test/dummy_host.cc |
@@ -0,0 +1,445 @@ |
+// 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.
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <cassert> |
+#include <iostream> |
+#include <memory> |
+#include <string> |
+#include <vector> |
+ |
+#include "base/at_exit.h" |
+#include "base/atomicops.h" |
+#include "base/bind.h" |
+#include "base/command_line.h" |
+#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "base/threading/platform_thread.h" |
+#include "base/time/time.h" |
+#include "remoting/base/auto_thread_task_runner.h" |
+#include "remoting/codec/video_encoder_verbatim.h" |
+#include "remoting/codec/video_encoder_vpx.h" |
+#include "remoting/host/chromoting_host.h" |
+#include "remoting/host/chromoting_host_context.h" |
+#include "remoting/host/client_session.h" |
+#include "remoting/host/host_extension.h" |
+#include "remoting/host/host_mock_objects.h" |
+#include "remoting/host/it2me_desktop_environment.h" |
+#include "remoting/host/resources.h" |
+#include "remoting/proto/audio.pb.h" |
+#include "remoting/protocol/audio_stub.h" |
+#include "remoting/protocol/fake_connection_to_client.h" |
+#include "remoting/protocol/pairing_registry.h" |
+#include "remoting/protocol/protocol_mock_objects.h" |
+#include "remoting/protocol/session_config.h" |
+#include "remoting/protocol/video_frame_pump.h" |
+#include "remoting/protocol/video_stub.h" |
+ |
+#if defined(OS_LINUX) |
+#include <gtk/gtk.h> |
+#include <X11/Xlib.h> |
+ |
+#include "base/linux_util.h" |
+#endif // defined(OS_LINUX) |
+ |
+using base::AtExitManager; |
+using base::Bind; |
+using base::Closure; |
+using base::CommandLine; |
+using base::MessageLoopForUI; |
+using base::RunLoop; |
+using base::TimeDelta; |
+using base::WrapUnique; |
+using google::protobuf::MessageLite; |
+using remoting::AudioPacket; |
+using remoting::ChromotingHostContext; |
+using remoting::ClientSession; |
+using remoting::HostExtension; |
+using remoting::MockClientSessionEventHandler; |
+using remoting::It2MeDesktopEnvironmentFactory; |
+using remoting::VideoAck; |
+using remoting::VideoEncoder; |
+using remoting::VideoEncoderVpx; |
+using remoting::VideoEncoderVerbatim; |
+using remoting::VideoPacket; |
+using remoting::protocol::AudioControl; |
+using remoting::protocol::AudioStub; |
+using remoting::protocol::Capabilities; |
+using remoting::protocol::ChannelConfig; |
+using remoting::protocol::ClientResolution; |
+using remoting::protocol::ClientStub; |
+using remoting::protocol::ClipboardEvent; |
+using remoting::protocol::ConnectionToClient; |
+using remoting::protocol::CursorShapeInfo; |
+using remoting::protocol::ExtensionMessage; |
+using remoting::protocol::FakeConnectionToClient; |
+using remoting::protocol::HostStub; |
+using remoting::protocol::MockClientStub; |
+using remoting::protocol::MockHostStub; |
+using remoting::protocol::MockSession; |
+using remoting::protocol::PairingRegistry; |
+using remoting::protocol::PairingRequest; |
+using remoting::protocol::PairingResponse; |
+using remoting::protocol::SessionConfig; |
+using remoting::protocol::VideoControl; |
+using remoting::protocol::VideoFeedbackStub; |
+using remoting::protocol::VideoFramePump; |
+using remoting::protocol::VideoLayout; |
+using remoting::protocol::VideoStream; |
+using remoting::protocol::VideoStub; |
+using std::cout; |
+using std::endl; |
+using std::move; |
+using std::string; |
+using std::vector; |
+using std::unique_ptr; |
+using testing::ReturnRef; |
+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
|
+ |
+namespace { |
+ |
+const bool g_output_to_stdout = false; |
+ |
+template <typename T> |
+class NoBarrierAtomic { |
+ public: |
+ T operator++() { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, 1) - 1; |
+ } |
+ |
+ T operator++(int) { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, 1); |
+ } |
+ |
+ T operator--() { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, -1) - 1; |
+ } |
+ |
+ T operator--(int) { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, -1); |
+ } |
+ |
+ T operator+=(T other) { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, other); |
+ } |
+ |
+ T operator-=(T other) { |
+ return base::subtle::NoBarrier_AtomicIncrement(&i, -other); |
+ } |
+ |
+ T operator*() const { |
+ return base::subtle::NoBarrier_Load(&i); |
+ } |
+ |
+ private: |
+ volatile T i; |
+}; |
+ |
+class NoBarrierAtomicInt32 : public NoBarrierAtomic<base::subtle::Atomic32> {}; |
+#if ARCH_CPU_64_BITS |
+class NoBarrierAtomicInt64 : public NoBarrierAtomic<base::subtle::Atomic64> {}; |
+#else |
+ |
+#include "base/synchronization/lock.h" |
+using base::AutoLock; |
+using base::Lock; |
+ |
+// A barriered, lock based implementation |
+class NoBarrierAtomicInt64 { |
+ public: |
+ int64_t operator++() { |
+ AutoLock l(lock); |
+ return i++; |
+ } |
+ |
+ int64_t operator++(int) { |
+ AutoLock l(lock); |
+ return ++i; |
+ } |
+ |
+ int64_t operator--() { |
+ AutoLock l(lock); |
+ return i--; |
+ } |
+ |
+ int64_t operator--(int) { |
+ AutoLock l(lock); |
+ return --i; |
+ } |
+ |
+ int64_t operator+=(int64_t other) { |
+ AutoLock l(lock); |
+ return (i += other); |
+ } |
+ |
+ int64_t operator-=(int64_t other) { |
+ AutoLock l(lock); |
+ return (i -= other); |
+ } |
+ |
+ int64_t operator*() const { |
+ base::subtle::MemoryBarrier(); |
+ return i; |
+ } |
+ |
+ private: |
+ volatile int64_t i; |
+ Lock lock; |
+}; |
+#endif |
+ |
+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
|
+ public: |
+ MessageLogger() |
+ : count_(), |
+ size_(), |
+ last_size_(), |
+ started_(base::Time::Now()) {} |
+ |
+ int message_count() const { |
+ return *count_; |
+ } |
+ |
+ int64_t message_size() const { |
+ return *size_; |
+ } |
+ |
+ int last_message_size() const { |
+ return last_size_; |
+ } |
+ |
+ double DurationSeconds() const { |
+ return (base::Time::Now() - started_).InSecondsF(); |
+ } |
+ |
+ protected: |
+ void LogMessage(const MessageLite& message) { |
+ count_++; |
+ last_size_ = message.ByteSize(); |
+ size_ += last_size_; |
+ } |
+ |
+ private: |
+ NoBarrierAtomicInt32 count_; |
+ NoBarrierAtomicInt64 size_; |
+ int last_size_; |
+ base::Time started_; |
+}; |
+ |
+class LogClientStub : public ClientStub, public MessageLogger { |
+ public: |
+ void SetCapabilities(const Capabilities& capabilities) override {} |
+ void SetPairingResponse(const PairingResponse& response) override {} |
+ void InjectClipboardEvent(const ClipboardEvent& event) override {} |
+ void SetCursorShape(const CursorShapeInfo& cursor_shape) override {} |
+ |
+ void DeliverHostMessage(const ExtensionMessage& message) override { |
+ if (g_output_to_stdout) { |
+ 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
|
+ } |
+ LogMessage(message); |
+ } |
+ |
+ void SetVideoLayout(const VideoLayout& video_layout) override {} |
+}; |
+ |
+class LogHostStub : public HostStub, public MessageLogger { |
+ public: |
+ void NotifyClientResolution(const ClientResolution& resolution) override {} |
+ void ControlVideo(const VideoControl& video_control) override {} |
+ void ControlAudio(const AudioControl& audio_control) override {} |
+ void SetCapabilities(const Capabilities& capabilities) override {} |
+ void RequestPairing(const PairingRequest& pairing_request) override {} |
+ |
+ void DeliverClientMessage(const ExtensionMessage& message) override { |
+ if (g_output_to_stdout) { |
+ cout << "DeliverClientMessage(" << message.ByteSize() << ")" << endl; |
+ } |
+ LogMessage(message); |
+ } |
+}; |
+ |
+class LogAudioStub : public AudioStub, public MessageLogger { |
+ public: |
+ void ProcessAudioPacket(unique_ptr<AudioPacket> audio_packet, |
+ const Closure& done) override { |
+ if (audio_packet) { |
+ if (g_output_to_stdout) { |
+ cout << "ProcessAudioPacket(" << audio_packet->data_size(); |
+ for (int i = 0; i < audio_packet->data_size(); i++) { |
+ cout << " - " << audio_packet->data(i).size(); |
+ } |
+ cout << ")" << endl; |
+ } |
+ LogMessage(*audio_packet); |
+ } |
+ done.Run(); |
+ } |
+}; |
+ |
+class LogVideoStub : public VideoStub, public MessageLogger { |
+ public: |
+ LogVideoStub(FakeConnectionToClient* connection) : connection_(connection) {} |
+ |
+ void ProcessVideoPacket(unique_ptr<VideoPacket> video_packet, |
+ const Closure& done) override { |
+ if (video_packet) { |
+ if (g_output_to_stdout) { |
+ cout << "ProcessVideoPacket(" |
+ << video_packet->data().size() |
+ << ")" |
+ << endl; |
+ } |
+ if (connection_ && connection_->video_feedback_stub()) { |
+ VideoAck* ack = new VideoAck(); |
+ ack->set_frame_id(video_packet->frame_id()); |
+ connection_->video_feedback_stub()->ProcessVideoAck(WrapUnique(ack)); |
+ } |
+ LogMessage(*video_packet); |
+ } |
+ done.Run(); |
+ } |
+ |
+ private: |
+ FakeConnectionToClient* connection_ = nullptr; |
+}; |
+ |
+// Stores all objects a host needs |
+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.
|
+ MessageLoopForUI message_loop; |
+ RunLoop run_loop; |
+ unique_ptr<ChromotingHostContext> context; |
+ It2MeDesktopEnvironmentFactory factory; |
+ FakeConnectionToClient connection; |
+ string session_jid; |
+ unique_ptr<SessionConfig> config; |
+ LogAudioStub audio_stub; |
+ LogVideoStub video_stub; |
+ LogClientStub client_stub; |
+ LogHostStub host_stub; |
+ MockClientSessionEventHandler handler; |
+ unique_ptr<ClientSession> session; |
+ |
+ Container() |
+ : message_loop(), |
+ run_loop(), |
+ context(ChromotingHostContext::Create( |
+ new remoting::AutoThreadTaskRunner( |
+ message_loop.task_runner(), run_loop.QuitClosure()))), |
+ factory(context->network_task_runner(), |
+ context->video_capture_task_runner(), |
+ context->input_task_runner(), |
+ context->ui_task_runner()), |
+ connection(WrapUnique(new MockSession())), |
+ session_jid("user@domain/rest-of-jid"), |
+#if defined(OS_LINUX) |
+ 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
|
+#else |
+ config(SessionConfig::ForTestWithAudio()), |
+#endif |
+ audio_stub(), |
+ video_stub(&connection), |
+ client_stub(), |
+ host_stub(), |
+ handler(), |
+ session() { |
+ 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.
|
+ .WillRepeatedly(ReturnRef(session_jid)); |
+ EXPECT_CALL(*static_cast<MockSession*>(connection.session()), config()) |
+ .WillRepeatedly(ReturnRef(*config)); |
+ connection.set_audio_stub(&audio_stub); |
+ connection.set_video_stub(&video_stub); |
+ connection.set_client_stub(&client_stub); |
+ connection.set_host_stub(&host_stub); |
+ connection.set_video_encode_task_runner( |
+ context->video_encode_task_runner()); |
+ } |
+ |
+ void CreateClientSession() { |
+ // 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
|
+ session.reset(new ClientSession( |
+ &handler, |
+ context->audio_task_runner(), |
+ unique_ptr<ConnectionToClient>(&connection), |
+ &factory, |
+ TimeDelta(), |
+ scoped_refptr<PairingRegistry>(), |
+ vector<HostExtension*>())); |
+ } |
+}; |
+ |
+void Execute(Container* container) { |
+ container->CreateClientSession(); |
+ container->session->OnConnectionAuthenticated(&container->connection); |
+ container->session->OnConnectionChannelsConnected(&container->connection); |
+ container->session->CreateVideoStreams(&container->connection); |
+} |
+ |
+void BindAnalysisResultOutputter(Container* container); |
+ |
+void OutputLogger(const char* name, const MessageLogger& logger) { |
+ cout << name |
+ << ": " |
+ << logger.message_size() |
+ << " bytes in " |
+ << logger.message_count() |
+ << " packages, last package " |
+ << logger.last_message_size() |
+ << " bytes, " |
+ << static_cast<double>(logger.message_size()) / logger.message_count() |
+ << " bytes/package, " |
+ << static_cast<double>(logger.message_count()) / logger.DurationSeconds() |
+ << " packages/sec, " |
+ << static_cast<double>(logger.message_size()) / logger.DurationSeconds() |
+ << " bytes/sec" |
+ << endl; |
+} |
+ |
+void OutputAnalysisResult(Container* container) { |
+ OutputLogger("audio", container->audio_stub); |
+ OutputLogger("video", container->video_stub); |
+ OutputLogger("client", container->client_stub); |
+ OutputLogger("host", container->host_stub); |
+ BindAnalysisResultOutputter(container); |
+} |
+ |
+void BindAnalysisResultOutputter(Container* container) { |
+ container->context->ui_task_runner()->PostDelayedTask( |
+ FROM_HERE, |
+ Bind(&OutputAnalysisResult, container), |
+ TimeDelta::FromSeconds(1)); |
+} |
+ |
+} // namespace |
+ |
+int main(int argc, const char** argv) { |
+ AtExitManager at_exit_manager; |
+ CommandLine::Init(argc, argv); |
+ 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.
|
+ Container container; |
+ |
+#if defined(OS_LINUX) |
+ // Required in order for us to run multiple X11 threads. |
+ XInitThreads(); |
+ |
+ // Required for any calls into GTK functions, such as the Disconnect and |
+ // Continue windows. Calling with nullptr arguments because we don't have |
+ // any command line arguments for gtk to consume. |
+ gtk_init(nullptr, nullptr); |
+ |
+ // Need to prime the host OS version value for linux to prevent IO on the |
+ // network thread. base::GetLinuxDistro() caches the result. |
+ base::GetLinuxDistro(); |
+#endif // OS_LINUX |
+ |
+ 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.
|
+ container.context->network_task_runner()->PostTask( |
+ FROM_HERE, |
+ Bind(&Execute, &container)); |
+ BindAnalysisResultOutputter(&container); |
+ container.run_loop.Run(); |
+} |