1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file. 4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/ios/bridge/client_instance.h" 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/bind.h" 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/logging.h" 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/socket/client_socket_factory.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/base/url_request_context.h" 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/client/audio_player.h" 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/client/plugin/delegating_signal_strategy.h" 14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/ios/bridge/client_proxy.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/jingle_glue/chromium_port_allocator.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/protocol/host_stub.h" 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/protocol/libjingle_transport_factory.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace { 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* const kXmppServer = "talk.google.com"; 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kXmppPort = 5222; 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const bool kXmppUseTls = true; 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DoNothing() {} 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace remoting { 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::ClientInstance(const base::WeakPtr<ClientProxy>& proxy, 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& username, 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& auth_token, 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& host_jid, 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& host_id, 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& host_pubkey, 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& pairing_id, 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& pairing_secret) 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : proxyToClient_(proxy), host_id_(host_id), create_pairing_(false) { 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!base::MessageLoop::current()) { 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Starting main message loop"; 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_loop_ = new base::MessageLoopForUI(); 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_loop_->Attach(); 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Using existing main message loop"; 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_loop_ = base::MessageLoopForUI::current(); 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Spawning additional threads"; 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |ui_loop_| runs on the main thread, so |ui_task_runner_| will run on the 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // main thread. We can not kill the main thread when the message loop becomes 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // idle so the callback function does nothing (as opposed to the typical 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // base::MessageLoop::QuitClosure()) 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&::DoNothing)); 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_ = AutoThread::CreateWithType( 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) "native_net", ui_task_runner_, base::MessageLoop::TYPE_IO); 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) url_requester_ = new URLRequestContextGetter(network_task_runner_); 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_context_.reset(new ClientContext(network_task_runner_)); 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(ui_task_runner_->BelongsToCurrentThread()); 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Initialize XMPP config. 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.host = kXmppServer; 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.port = kXmppPort; 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.use_tls = kXmppUseTls; 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.username = username; 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.auth_token = auth_token; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_.auth_service = "oauth2"; 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Initialize ClientConfig. 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.host_jid = host_jid; 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.host_public_key = host_pubkey; 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.authentication_tag = host_id_; 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.client_pairing_id = pairing_id; 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.client_paired_secret = pairing_secret; 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.authentication_methods.push_back( 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::AuthenticationMethod::FromString("spake2_pair")); 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.authentication_methods.push_back( 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::AuthenticationMethod::FromString("spake2_hmac")); 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.authentication_methods.push_back( 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::AuthenticationMethod::FromString("spake2_plain")); 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::~ClientInstance() {} 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::Start() { 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(ui_task_runner_->BelongsToCurrentThread()); 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Creates a reference to |this|, so don't want to bind during constructor 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.fetch_secret_callback = 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::FetchSecret, this); 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) view_.reset(new FrameConsumerBridge( 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientProxy::RedrawCanvas, proxyToClient_))); 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |consumer_proxy| must be created on the UI thread to proxy calls from the 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // network or decode thread to the UI thread, but ownership will belong to a 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // SoftwareVideoRenderer which runs on the network thread. 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_refptr<FrameConsumerProxy> consumer_proxy = 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new FrameConsumerProxy(ui_task_runner_, view_->AsWeakPtr()); 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Post a task to start connection 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::WaitableEvent done_event(true, false); 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_->PostTask( 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::ConnectToHostOnNetworkThread, 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this, 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) consumer_proxy, 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&base::WaitableEvent::Signal, 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Unretained(&done_event)))); 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Wait until initialization completes before continuing 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) done_event.Wait(); 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::Cleanup() { 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(ui_task_runner_->BelongsToCurrentThread()); 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_config_.fetch_secret_callback.Reset(); // Release ref to this 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |view_| must be destroyed on the UI thread before the producer is gone. 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) view_.reset(); 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::WaitableEvent done_event(true, false); 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_->PostTask( 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::DisconnectFromHostOnNetworkThread, 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this, 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&base::WaitableEvent::Signal, 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Unretained(&done_event)))); 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Wait until we are fully disconnected before continuing 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) done_event.Wait(); 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// HOST attempts to continue automatically with previously supplied credentials, 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// if it can't it requests the user's PIN. 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::FetchSecret( 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool pairable, 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const protocol::SecretFetchedCallback& callback) { 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!ui_task_runner_->BelongsToCurrentThread()) { 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_task_runner_->PostTask( 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::FetchSecret, this, pairable, callback)); 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) pin_callback_ = callback; 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (proxyToClient_) { 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!client_config_.client_pairing_id.empty()) { 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We attempted to connect using an existing pairing that was rejected. 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Unless we forget about the stale credentials, we'll continue trying 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // them. 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Deleting rejected pairing credentials"; 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) proxyToClient_->CommitPairingCredentials(host_id_, "", ""); 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) proxyToClient_->DisplayAuthenticationPrompt(pairable); 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::ProvideSecret(const std::string& pin, 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool create_pairing) { 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(ui_task_runner_->BelongsToCurrentThread()); 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) create_pairing_ = create_pairing; 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Before this function can complete, FetchSecret must be called 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!pin_callback_.is_null()); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_->PostTask(FROM_HERE, base::Bind(pin_callback_, pin)); 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::PerformMouseAction( 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const webrtc::DesktopVector& position, 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const webrtc::DesktopVector& wheel_delta, 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int /* protocol::MouseEvent_MouseButton */ whichButton, 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool button_down) { 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!network_task_runner_->BelongsToCurrentThread()) { 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_->PostTask( 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::PerformMouseAction, 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this, 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) position, 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wheel_delta, 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) whichButton, 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) button_down)); 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::MouseEvent_MouseButton mButton; 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Button must be within the bounds of the MouseEvent_MouseButton enum. 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (whichButton) { 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT: 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT; 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX: 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX; 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MIDDLE: 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = protocol::MouseEvent_MouseButton:: 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MouseEvent_MouseButton_BUTTON_MIDDLE; 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT: 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT; 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case protocol::MouseEvent_MouseButton:: 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MouseEvent_MouseButton_BUTTON_UNDEFINED: 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = protocol::MouseEvent_MouseButton:: 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MouseEvent_MouseButton_BUTTON_UNDEFINED; 215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LOG(FATAL) << "Invalid constant for MouseEvent_MouseButton"; 218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mButton = protocol::MouseEvent_MouseButton:: 219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MouseEvent_MouseButton_BUTTON_UNDEFINED; 220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::MouseEvent action; 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_x(position.x()); 225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_y(position.y()); 226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_wheel_delta_x(wheel_delta.x()); 227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_wheel_delta_y(wheel_delta.y()); 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_button(mButton); 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mButton != protocol::MouseEvent::BUTTON_UNDEFINED) 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_button_down(button_down); 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connection_->input_stub()->InjectMouseEvent(action); 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::PerformKeyboardAction(int key_code, bool key_down) { 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!network_task_runner_->BelongsToCurrentThread()) { 237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_task_runner_->PostTask( 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind( 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &ClientInstance::PerformKeyboardAction, this, key_code, key_down)); 241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::KeyEvent action; 245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_usb_keycode(key_code); 246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) action.set_pressed(key_down); 247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connection_->input_stub()->InjectKeyEvent(action); 248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnConnectionState(protocol::ConnectionToHost::State state, 251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) protocol::ErrorCode error) { 252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!ui_task_runner_->BelongsToCurrentThread()) { 253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_task_runner_->PostTask( 254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::OnConnectionState, this, state, error)); 256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO (aboone) This functionality is not scheduled for QA yet. 260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) { 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // VLOG(1) << "Attempting to pair with host"; 262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // protocol::PairingRequest request; 263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // request.set_client_name("iOS"); 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // connection_->host_stub()->RequestPairing(request); 265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // } 266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (proxyToClient_) 268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) proxyToClient_->ReportConnectionStatus(state, error); 269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnConnectionReady(bool ready) { 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We ignore this message, since OnConnectionState tells us the same thing. 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnRouteChanged(const std::string& channel_name, 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const protocol::TransportRoute& route) { 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Using " << protocol::TransportRoute::GetTypeString(route.type) 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << " connection for " << channel_name << " channel"; 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetCapabilities(const std::string& capabilities) { 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(video_renderer_); 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(connection_); 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(connection_->state() == protocol::ConnectionToHost::CONNECTED); 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) video_renderer_->Initialize(connection_->config()); 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetPairingResponse( 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const protocol::PairingResponse& response) { 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!ui_task_runner_->BelongsToCurrentThread()) { 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_task_runner_->PostTask( 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ClientInstance::SetPairingResponse, this, response)); 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(1) << "Successfully established pairing with host"; 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (proxyToClient_) 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) proxyToClient_->CommitPairingCredentials( 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) host_id_, response.client_id(), response.shared_secret()); 302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::DeliverHostMessage( 305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const protocol::ExtensionMessage& message) { 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NOTIMPLEMENTED(); 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returning interface of protocol::ClipboardStub 310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)protocol::ClipboardStub* ClientInstance::GetClipboardStub() { return this; } 311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returning interface of protocol::CursorShapeStub 313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)protocol::CursorShapeStub* ClientInstance::GetCursorShapeStub() { return this; } 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::GetTokenFetcher(const std::string& host_public_key) { 317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Returns null when third-party authentication is unsupported. 318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::InjectClipboardEvent( 322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const protocol::ClipboardEvent& event) { 323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NOTIMPLEMENTED(); 324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetCursorShape(const protocol::CursorShapeInfo& shape) { 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!ui_task_runner_->BelongsToCurrentThread()) { 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ui_task_runner_->PostTask( 329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, base::Bind(&ClientInstance::SetCursorShape, this, shape)); 330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (proxyToClient_) 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) proxyToClient_->UpdateCursorShape(shape); 334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::ConnectToHostOnNetworkThread( 337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_refptr<FrameConsumerProxy> consumer_proxy, 338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::Closure& done) { 339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(network_task_runner_->BelongsToCurrentThread()); 340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_context_->Start(); 342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) video_renderer_.reset( 344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new SoftwareVideoRenderer(client_context_->main_task_runner(), 345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_context_->decode_task_runner(), 346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) consumer_proxy)); 347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) view_->Initialize(video_renderer_.get()); 349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connection_.reset(new protocol::ConnectionToHost(true)); 351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_.reset(new ChromotingClient(client_config_, 353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_context_.get(), 354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connection_.get(), 355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) this, 356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) video_renderer_.get(), 357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<AudioPlayer>())); 358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) signaling_.reset( 360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(), 361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) url_requester_, 362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) xmpp_config_)); 363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED); 365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<ChromiumPortAllocator> port_allocator( 367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ChromiumPortAllocator::Create(url_requester_, network_settings)); 368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<protocol::TransportFactory> transport_factory( 370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new protocol::LibjingleTransportFactory( 371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) signaling_.get(), 372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) port_allocator.PassAs<cricket::HttpPortAllocatorBase>(), 373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) network_settings)); 374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_->Start(signaling_.get(), transport_factory.Pass()); 376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!done.is_null()) 378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) done.Run(); 379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::DisconnectFromHostOnNetworkThread( 382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::Closure& done) { 383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(network_task_runner_->BelongsToCurrentThread()); 384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) host_id_.clear(); 386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |client_| must be torn down before |signaling_|. 388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) connection_.reset(); 389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_.reset(); 390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) signaling_.reset(); 391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) video_renderer_.reset(); 392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) client_context_->Stop(); 393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!done.is_null()) 394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) done.Run(); 395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace remoting 398