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 3 // found in the LICENSE file. 4 5 #include "content/browser/gamepad/gamepad_service.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/memory/singleton.h" 10 #include "content/browser/gamepad/gamepad_consumer.h" 11 #include "content/browser/gamepad/gamepad_data_fetcher.h" 12 #include "content/browser/gamepad/gamepad_provider.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/render_process_host.h" 15 16 namespace content { 17 18 namespace { 19 GamepadService* g_gamepad_service = 0; 20 } 21 22 GamepadService::GamepadService() 23 : num_active_consumers_(0), 24 gesture_callback_pending_(false) { 25 SetInstance(this); 26 } 27 28 GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher) 29 : provider_(new GamepadProvider(fetcher.Pass())), 30 num_active_consumers_(0), 31 gesture_callback_pending_(false) { 32 SetInstance(this); 33 thread_checker_.DetachFromThread(); 34 } 35 36 GamepadService::~GamepadService() { 37 SetInstance(NULL); 38 } 39 40 void GamepadService::SetInstance(GamepadService* instance) { 41 // Unit tests can create multiple instances but only one should exist at any 42 // given time so g_gamepad_service should only go from NULL to non-NULL and 43 // vica versa. 44 CHECK(!!instance != !!g_gamepad_service); 45 g_gamepad_service = instance; 46 } 47 48 GamepadService* GamepadService::GetInstance() { 49 if (!g_gamepad_service) 50 g_gamepad_service = new GamepadService; 51 return g_gamepad_service; 52 } 53 54 void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) { 55 DCHECK(thread_checker_.CalledOnValidThread()); 56 57 if (!provider_) 58 provider_.reset(new GamepadProvider); 59 60 std::pair<ConsumerSet::iterator, bool> insert_result = 61 consumers_.insert(consumer); 62 insert_result.first->is_active = true; 63 if (!insert_result.first->did_observe_user_gesture && 64 !gesture_callback_pending_) { 65 gesture_callback_pending_ = true; 66 provider_->RegisterForUserGesture( 67 base::Bind(&GamepadService::OnUserGesture, 68 base::Unretained(this))); 69 } 70 71 if (num_active_consumers_++ == 0) 72 provider_->Resume(); 73 } 74 75 void GamepadService::ConsumerBecameInactive(GamepadConsumer* consumer) { 76 DCHECK(provider_); 77 DCHECK(num_active_consumers_ > 0); 78 DCHECK(consumers_.count(consumer) > 0); 79 DCHECK(consumers_.find(consumer)->is_active); 80 81 consumers_.find(consumer)->is_active = false; 82 if (--num_active_consumers_ == 0) 83 provider_->Pause(); 84 } 85 86 void GamepadService::RemoveConsumer(GamepadConsumer* consumer) { 87 DCHECK(thread_checker_.CalledOnValidThread()); 88 89 ConsumerSet::iterator it = consumers_.find(consumer); 90 if (it->is_active && --num_active_consumers_ == 0) 91 provider_->Pause(); 92 consumers_.erase(it); 93 } 94 95 void GamepadService::RegisterForUserGesture(const base::Closure& closure) { 96 DCHECK(consumers_.size() > 0); 97 DCHECK(thread_checker_.CalledOnValidThread()); 98 provider_->RegisterForUserGesture(closure); 99 } 100 101 void GamepadService::Terminate() { 102 provider_.reset(); 103 } 104 105 void GamepadService::OnGamepadConnected( 106 int index, 107 const blink::WebGamepad& pad) { 108 DCHECK(thread_checker_.CalledOnValidThread()); 109 110 for (ConsumerSet::iterator it = consumers_.begin(); 111 it != consumers_.end(); ++it) { 112 if (it->did_observe_user_gesture && it->is_active) 113 it->consumer->OnGamepadConnected(index, pad); 114 } 115 } 116 117 void GamepadService::OnGamepadDisconnected( 118 int index, 119 const blink::WebGamepad& pad) { 120 DCHECK(thread_checker_.CalledOnValidThread()); 121 122 for (ConsumerSet::iterator it = consumers_.begin(); 123 it != consumers_.end(); ++it) { 124 if (it->did_observe_user_gesture && it->is_active) 125 it->consumer->OnGamepadDisconnected(index, pad); 126 } 127 } 128 129 base::SharedMemoryHandle GamepadService::GetSharedMemoryHandleForProcess( 130 base::ProcessHandle handle) { 131 DCHECK(thread_checker_.CalledOnValidThread()); 132 return provider_->GetSharedMemoryHandleForProcess(handle); 133 } 134 135 void GamepadService::OnUserGesture() { 136 DCHECK(thread_checker_.CalledOnValidThread()); 137 138 gesture_callback_pending_ = false; 139 140 if (!provider_ || 141 num_active_consumers_ == 0) 142 return; 143 144 for (ConsumerSet::iterator it = consumers_.begin(); 145 it != consumers_.end(); ++it) { 146 if (!it->did_observe_user_gesture && it->is_active) { 147 const ConsumerInfo& info = *it; 148 info.did_observe_user_gesture = true; 149 blink::WebGamepads gamepads; 150 provider_->GetCurrentGamepadData(&gamepads); 151 for (unsigned i = 0; i < blink::WebGamepads::itemsLengthCap; ++i) { 152 const blink::WebGamepad& pad = gamepads.items[i]; 153 if (pad.connected) 154 info.consumer->OnGamepadConnected(i, pad); 155 } 156 } 157 } 158 } 159 160 } // namespace content 161