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 |