| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/client/plugin/chromoting_instance.h" | 5 #include "remoting/client/plugin/chromoting_instance.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 LOG(ERROR) << "No valid authentication methods specified."; | 145 LOG(ERROR) << "No valid authentication methods specified."; |
| 146 return false; | 146 return false; |
| 147 } | 147 } |
| 148 | 148 |
| 149 return true; | 149 return true; |
| 150 } | 150 } |
| 151 | 151 |
| 152 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) | 152 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
| 153 : pp::Instance(pp_instance), | 153 : pp::Instance(pp_instance), |
| 154 initialized_(false), | 154 initialized_(false), |
| 155 plugin_message_loop_( | 155 plugin_task_runner_( |
| 156 new PluginMessageLoopProxy(&plugin_thread_delegate_)), | 156 new PluginThreadTaskRunner(&plugin_thread_delegate_)), |
| 157 context_(plugin_message_loop_), | 157 context_(plugin_task_runner_), |
| 158 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 158 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 159 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); | 159 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
| 160 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 160 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
| 161 | 161 |
| 162 // Resister this instance to handle debug log messsages. | 162 // Resister this instance to handle debug log messsages. |
| 163 RegisterLoggingInstance(); | 163 RegisterLoggingInstance(); |
| 164 | 164 |
| 165 // Send hello message. | 165 // Send hello message. |
| 166 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 166 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 167 data->SetInteger("apiVersion", kApiVersion); | 167 data->SetInteger("apiVersion", kApiVersion); |
| 168 data->SetString("apiFeatures", kApiFeatures); | 168 data->SetString("apiFeatures", kApiFeatures); |
| 169 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); | 169 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); |
| 170 PostChromotingMessage("hello", data.Pass()); | 170 PostChromotingMessage("hello", data.Pass()); |
| 171 } | 171 } |
| 172 | 172 |
| 173 ChromotingInstance::~ChromotingInstance() { | 173 ChromotingInstance::~ChromotingInstance() { |
| 174 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 174 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 175 | 175 |
| 176 // Unregister this instance so that debug log messages will no longer be sent | 176 // Unregister this instance so that debug log messages will no longer be sent |
| 177 // to it. This will stop all logging in all Chromoting instances. | 177 // to it. This will stop all logging in all Chromoting instances. |
| 178 UnregisterLoggingInstance(); | 178 UnregisterLoggingInstance(); |
| 179 | 179 |
| 180 // PepperView must be destroyed before the client. | 180 // PepperView must be destroyed before the client. |
| 181 view_.reset(); | 181 view_.reset(); |
| 182 | 182 |
| 183 if (client_.get()) { | 183 if (client_.get()) { |
| 184 base::WaitableEvent done_event(true, false); | 184 base::WaitableEvent done_event(true, false); |
| 185 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 185 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
| 186 base::Unretained(&done_event))); | 186 base::Unretained(&done_event))); |
| 187 done_event.Wait(); | 187 done_event.Wait(); |
| 188 } | 188 } |
| 189 | 189 |
| 190 // Stopping the context shuts down all chromoting threads. | 190 // Stopping the context shuts down all chromoting threads. |
| 191 context_.Stop(); | 191 context_.Stop(); |
| 192 | 192 |
| 193 // Ensure that nothing touches the plugin thread delegate after this point. | 193 // Ensure that nothing touches the plugin thread delegate after this point. |
| 194 plugin_message_loop_->Detach(); | 194 plugin_task_runner_->Detach(); |
| 195 } | 195 } |
| 196 | 196 |
| 197 bool ChromotingInstance::Init(uint32_t argc, | 197 bool ChromotingInstance::Init(uint32_t argc, |
| 198 const char* argn[], | 198 const char* argn[], |
| 199 const char* argv[]) { | 199 const char* argv[]) { |
| 200 CHECK(!initialized_); | 200 CHECK(!initialized_); |
| 201 initialized_ = true; | 201 initialized_ = true; |
| 202 | 202 |
| 203 VLOG(1) << "Started ChromotingInstance::Init"; | 203 VLOG(1) << "Started ChromotingInstance::Init"; |
| 204 | 204 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 216 // which case, there may be a slight race. | 216 // which case, there may be a slight race. |
| 217 net::EnableSSLServerSockets(); | 217 net::EnableSSLServerSockets(); |
| 218 | 218 |
| 219 // Start all the threads. | 219 // Start all the threads. |
| 220 context_.Start(); | 220 context_.Start(); |
| 221 | 221 |
| 222 // Create the chromoting objects that don't depend on the network connection. | 222 // Create the chromoting objects that don't depend on the network connection. |
| 223 // RectangleUpdateDecoder runs on a separate thread so for now we wrap | 223 // RectangleUpdateDecoder runs on a separate thread so for now we wrap |
| 224 // PepperView with a ref-counted proxy object. | 224 // PepperView with a ref-counted proxy object. |
| 225 scoped_refptr<FrameConsumerProxy> consumer_proxy = | 225 scoped_refptr<FrameConsumerProxy> consumer_proxy = |
| 226 new FrameConsumerProxy(plugin_message_loop_); | 226 new FrameConsumerProxy(plugin_task_runner_); |
| 227 rectangle_decoder_ = new RectangleUpdateDecoder( | 227 rectangle_decoder_ = new RectangleUpdateDecoder( |
| 228 context_.decode_task_runner(), consumer_proxy); | 228 context_.decode_task_runner(), consumer_proxy); |
| 229 view_.reset(new PepperView(this, &context_, rectangle_decoder_.get())); | 229 view_.reset(new PepperView(this, &context_, rectangle_decoder_.get())); |
| 230 consumer_proxy->Attach(view_->AsWeakPtr()); | 230 consumer_proxy->Attach(view_->AsWeakPtr()); |
| 231 | 231 |
| 232 return true; | 232 return true; |
| 233 } | 233 } |
| 234 | 234 |
| 235 void ChromotingInstance::HandleMessage(const pp::Var& message) { | 235 void ChromotingInstance::HandleMessage(const pp::Var& message) { |
| 236 if (!message.is_string()) { | 236 if (!message.is_string()) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 bool pause = false; | 335 bool pause = false; |
| 336 if (!data->GetBoolean("pause", &pause)) { | 336 if (!data->GetBoolean("pause", &pause)) { |
| 337 LOG(ERROR) << "Invalid pauseVideo."; | 337 LOG(ERROR) << "Invalid pauseVideo."; |
| 338 return; | 338 return; |
| 339 } | 339 } |
| 340 PauseVideo(pause); | 340 PauseVideo(pause); |
| 341 } | 341 } |
| 342 } | 342 } |
| 343 | 343 |
| 344 void ChromotingInstance::DidChangeView(const pp::View& view) { | 344 void ChromotingInstance::DidChangeView(const pp::View& view) { |
| 345 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 345 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 346 | 346 |
| 347 view_->SetView(view); | 347 view_->SetView(view); |
| 348 | 348 |
| 349 if (mouse_input_filter_.get()) { | 349 if (mouse_input_filter_.get()) { |
| 350 mouse_input_filter_->set_input_size(view_->get_view_size_dips()); | 350 mouse_input_filter_->set_input_size(view_->get_view_size_dips()); |
| 351 } | 351 } |
| 352 } | 352 } |
| 353 | 353 |
| 354 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { | 354 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { |
| 355 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 355 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 356 | 356 |
| 357 if (!IsConnected()) | 357 if (!IsConnected()) |
| 358 return false; | 358 return false; |
| 359 | 359 |
| 360 // TODO(wez): When we have a good hook into Host dimensions changes, move | 360 // TODO(wez): When we have a good hook into Host dimensions changes, move |
| 361 // this there. | 361 // this there. |
| 362 // If |input_handler_| is valid, then |mouse_input_filter_| must also be | 362 // If |input_handler_| is valid, then |mouse_input_filter_| must also be |
| 363 // since they are constructed together as part of the input pipeline | 363 // since they are constructed together as part of the input pipeline |
| 364 mouse_input_filter_->set_output_size(view_->get_screen_size()); | 364 mouse_input_filter_->set_output_size(view_->get_screen_size()); |
| 365 | 365 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 cursor_image, | 458 cursor_image, |
| 459 pp::Point(hotspot_x, hotspot_y)); | 459 pp::Point(hotspot_x, hotspot_y)); |
| 460 } | 460 } |
| 461 | 461 |
| 462 void ChromotingInstance::OnFirstFrameReceived() { | 462 void ChromotingInstance::OnFirstFrameReceived() { |
| 463 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 463 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 464 PostChromotingMessage("onFirstFrameReceived", data.Pass()); | 464 PostChromotingMessage("onFirstFrameReceived", data.Pass()); |
| 465 } | 465 } |
| 466 | 466 |
| 467 void ChromotingInstance::Connect(const ClientConfig& config) { | 467 void ChromotingInstance::Connect(const ClientConfig& config) { |
| 468 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 468 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 469 | 469 |
| 470 jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); | 470 jingle_glue::JingleThreadWrapper::EnsureForCurrentThread(); |
| 471 | 471 |
| 472 host_connection_.reset(new protocol::ConnectionToHost(true)); | 472 host_connection_.reset(new protocol::ConnectionToHost(true)); |
| 473 audio_player_.reset(new PepperAudioPlayer(this)); | 473 audio_player_.reset(new PepperAudioPlayer(this)); |
| 474 client_.reset(new ChromotingClient(config, context_.main_task_runner(), | 474 client_.reset(new ChromotingClient(config, context_.main_task_runner(), |
| 475 host_connection_.get(), this, | 475 host_connection_.get(), this, |
| 476 rectangle_decoder_.get(), | 476 rectangle_decoder_.get(), |
| 477 audio_player_.get())); | 477 audio_player_.get())); |
| 478 | 478 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 494 #endif | 494 #endif |
| 495 input_handler_.reset( | 495 input_handler_.reset( |
| 496 new PepperInputHandler(&key_mapper_)); | 496 new PepperInputHandler(&key_mapper_)); |
| 497 | 497 |
| 498 LOG(INFO) << "Connecting to " << config.host_jid | 498 LOG(INFO) << "Connecting to " << config.host_jid |
| 499 << ". Local jid: " << config.local_jid << "."; | 499 << ". Local jid: " << config.local_jid << "."; |
| 500 | 500 |
| 501 // Setup the XMPP Proxy. | 501 // Setup the XMPP Proxy. |
| 502 xmpp_proxy_ = new PepperXmppProxy( | 502 xmpp_proxy_ = new PepperXmppProxy( |
| 503 base::Bind(&ChromotingInstance::SendOutgoingIq, AsWeakPtr()), | 503 base::Bind(&ChromotingInstance::SendOutgoingIq, AsWeakPtr()), |
| 504 plugin_message_loop_, context_.main_task_runner()); | 504 plugin_task_runner_, context_.main_task_runner()); |
| 505 | 505 |
| 506 scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator( | 506 scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator( |
| 507 PepperPortAllocator::Create(this)); | 507 PepperPortAllocator::Create(this)); |
| 508 scoped_ptr<protocol::TransportFactory> transport_factory( | 508 scoped_ptr<protocol::TransportFactory> transport_factory( |
| 509 new protocol::LibjingleTransportFactory(port_allocator.Pass(), false)); | 509 new protocol::LibjingleTransportFactory(port_allocator.Pass(), false)); |
| 510 | 510 |
| 511 // Kick off the connection. | 511 // Kick off the connection. |
| 512 client_->Start(xmpp_proxy_, transport_factory.Pass()); | 512 client_->Start(xmpp_proxy_, transport_factory.Pass()); |
| 513 | 513 |
| 514 // Start timer that periodically sends perf stats. | 514 // Start timer that periodically sends perf stats. |
| 515 plugin_message_loop_->PostDelayedTask( | 515 plugin_task_runner_->PostDelayedTask( |
| 516 FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), | 516 FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), |
| 517 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs)); | 517 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs)); |
| 518 } | 518 } |
| 519 | 519 |
| 520 void ChromotingInstance::Disconnect() { | 520 void ChromotingInstance::Disconnect() { |
| 521 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 521 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 522 | 522 |
| 523 // PepperView must be destroyed before the client. | 523 // PepperView must be destroyed before the client. |
| 524 view_.reset(); | 524 view_.reset(); |
| 525 | 525 |
| 526 LOG(INFO) << "Disconnecting from host."; | 526 LOG(INFO) << "Disconnecting from host."; |
| 527 if (client_.get()) { | 527 if (client_.get()) { |
| 528 // TODO(sergeyu): Should we disconnect asynchronously? | 528 // TODO(sergeyu): Should we disconnect asynchronously? |
| 529 base::WaitableEvent done_event(true, false); | 529 base::WaitableEvent done_event(true, false); |
| 530 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 530 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
| 531 base::Unretained(&done_event))); | 531 base::Unretained(&done_event))); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 623 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 624 data->SetString("iq", iq); | 624 data->SetString("iq", iq); |
| 625 PostChromotingMessage("sendOutgoingIq", data.Pass()); | 625 PostChromotingMessage("sendOutgoingIq", data.Pass()); |
| 626 } | 626 } |
| 627 | 627 |
| 628 void ChromotingInstance::SendPerfStats() { | 628 void ChromotingInstance::SendPerfStats() { |
| 629 if (!client_.get()) { | 629 if (!client_.get()) { |
| 630 return; | 630 return; |
| 631 } | 631 } |
| 632 | 632 |
| 633 plugin_message_loop_->PostDelayedTask( | 633 plugin_task_runner_->PostDelayedTask( |
| 634 FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), | 634 FROM_HERE, base::Bind(&ChromotingInstance::SendPerfStats, AsWeakPtr()), |
| 635 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs)); | 635 base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs)); |
| 636 | 636 |
| 637 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 637 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 638 ChromotingStats* stats = client_->GetStats(); | 638 ChromotingStats* stats = client_->GetStats(); |
| 639 data->SetDouble("videoBandwidth", stats->video_bandwidth()->Rate()); | 639 data->SetDouble("videoBandwidth", stats->video_bandwidth()->Rate()); |
| 640 data->SetDouble("videoFrameRate", stats->video_frame_rate()->Rate()); | 640 data->SetDouble("videoFrameRate", stats->video_frame_rate()->Rate()); |
| 641 data->SetDouble("captureLatency", stats->video_capture_ms()->Average()); | 641 data->SetDouble("captureLatency", stats->video_capture_ms()->Average()); |
| 642 data->SetDouble("encodeLatency", stats->video_encode_ms()->Average()); | 642 data->SetDouble("encodeLatency", stats->video_encode_ms()->Average()); |
| 643 data->SetDouble("decodeLatency", stats->video_decode_ms()->Average()); | 643 data->SetDouble("decodeLatency", stats->video_decode_ms()->Average()); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 661 } | 661 } |
| 662 | 662 |
| 663 void ChromotingInstance::RegisterLoggingInstance() { | 663 void ChromotingInstance::RegisterLoggingInstance() { |
| 664 base::AutoLock lock(g_logging_lock.Get()); | 664 base::AutoLock lock(g_logging_lock.Get()); |
| 665 | 665 |
| 666 // Register this instance as the one that will handle all logging calls | 666 // Register this instance as the one that will handle all logging calls |
| 667 // and display them to the user. | 667 // and display them to the user. |
| 668 // If multiple plugins are run, then the last one registered will handle all | 668 // If multiple plugins are run, then the last one registered will handle all |
| 669 // logging for all instances. | 669 // logging for all instances. |
| 670 g_logging_instance.Get() = weak_factory_.GetWeakPtr(); | 670 g_logging_instance.Get() = weak_factory_.GetWeakPtr(); |
| 671 g_logging_task_runner.Get() = plugin_message_loop_; | 671 g_logging_task_runner.Get() = plugin_task_runner_; |
| 672 g_has_logging_instance = true; | 672 g_has_logging_instance = true; |
| 673 } | 673 } |
| 674 | 674 |
| 675 void ChromotingInstance::UnregisterLoggingInstance() { | 675 void ChromotingInstance::UnregisterLoggingInstance() { |
| 676 base::AutoLock lock(g_logging_lock.Get()); | 676 base::AutoLock lock(g_logging_lock.Get()); |
| 677 | 677 |
| 678 // Don't unregister unless we're the currently registered instance. | 678 // Don't unregister unless we're the currently registered instance. |
| 679 if (this != g_logging_instance.Get().get()) | 679 if (this != g_logging_instance.Get().get()) |
| 680 return; | 680 return; |
| 681 | 681 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 logging_instance, message)); | 728 logging_instance, message)); |
| 729 } | 729 } |
| 730 } | 730 } |
| 731 | 731 |
| 732 if (g_logging_old_handler) | 732 if (g_logging_old_handler) |
| 733 return (g_logging_old_handler)(severity, file, line, message_start, str); | 733 return (g_logging_old_handler)(severity, file, line, message_start, str); |
| 734 return false; | 734 return false; |
| 735 } | 735 } |
| 736 | 736 |
| 737 void ChromotingInstance::ProcessLogToUI(const std::string& message) { | 737 void ChromotingInstance::ProcessLogToUI(const std::string& message) { |
| 738 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 738 DCHECK(plugin_task_runner_->BelongsToCurrentThread()); |
| 739 | 739 |
| 740 // This flag (which is set only here) is used to prevent LogToUI from posting | 740 // This flag (which is set only here) is used to prevent LogToUI from posting |
| 741 // new tasks while we're in the middle of servicing a LOG call. This can | 741 // new tasks while we're in the middle of servicing a LOG call. This can |
| 742 // happen if the call to LogDebugInfo tries to LOG anything. | 742 // happen if the call to LogDebugInfo tries to LOG anything. |
| 743 // Since it is read on the plugin thread, we don't need to lock to set it. | 743 // Since it is read on the plugin thread, we don't need to lock to set it. |
| 744 g_logging_to_plugin = true; | 744 g_logging_to_plugin = true; |
| 745 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 745 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 746 data->SetString("message", message); | 746 data->SetString("message", message); |
| 747 PostChromotingMessage("logDebugMessage", data.Pass()); | 747 PostChromotingMessage("logDebugMessage", data.Pass()); |
| 748 g_logging_to_plugin = false; | 748 g_logging_to_plugin = false; |
| 749 } | 749 } |
| 750 | 750 |
| 751 bool ChromotingInstance::IsConnected() { | 751 bool ChromotingInstance::IsConnected() { |
| 752 return host_connection_.get() && | 752 return host_connection_.get() && |
| 753 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); | 753 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); |
| 754 } | 754 } |
| 755 | 755 |
| 756 } // namespace remoting | 756 } // namespace remoting |
| OLD | NEW |