Chromium Code Reviews| 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(); |
| +} |