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.
10 #include "base/logging.h"
11 #include "base/message_loop.h"
12 #include "base/message_loop_proxy.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "content/browser/gamepad/gamepad_data_fetcher.h"
16 #include "content/browser/gamepad/gamepad_provider.h"
17 #include "content/browser/gamepad/gamepad_platform_data_fetcher.h"
18 #include "content/common/gamepad_hardware_buffer.h"
19 #include "content/common/gamepad_messages.h"
20 #include "content/common/gamepad_user_gesture.h"
21 #include "content/public/browser/browser_thread.h"
25 GamepadProvider::ClosureAndThread::ClosureAndThread(
26 const base::Closure
& c
,
27 const scoped_refptr
<base::MessageLoopProxy
>& m
)
32 GamepadProvider::ClosureAndThread::~ClosureAndThread() {
35 GamepadProvider::GamepadProvider()
37 have_scheduled_do_poll_(false),
38 devices_changed_(true) {
39 Initialize(scoped_ptr
<GamepadDataFetcher
>());
42 GamepadProvider::GamepadProvider(scoped_ptr
<GamepadDataFetcher
> fetcher
)
44 have_scheduled_do_poll_(false),
45 devices_changed_(true) {
46 Initialize(fetcher
.Pass());
49 GamepadProvider::~GamepadProvider() {
50 base::SystemMonitor
* monitor
= base::SystemMonitor::Get();
52 monitor
->RemoveDevicesChangedObserver(this);
54 polling_thread_
.reset();
55 data_fetcher_
.reset();
58 base::SharedMemoryHandle
GamepadProvider::GetSharedMemoryHandleForProcess(
59 base::ProcessHandle process
) {
60 base::SharedMemoryHandle renderer_handle
;
61 gamepad_shared_memory_
.ShareToProcess(process
, &renderer_handle
);
62 return renderer_handle
;
65 void GamepadProvider::Pause() {
67 base::AutoLock
lock(is_paused_lock_
);
70 MessageLoop
* polling_loop
= polling_thread_
->message_loop();
71 polling_loop
->PostTask(
73 base::Bind(&GamepadProvider::SendPauseHint
, Unretained(this), true));
76 void GamepadProvider::Resume() {
78 base::AutoLock
lock(is_paused_lock_
);
84 MessageLoop
* polling_loop
= polling_thread_
->message_loop();
85 polling_loop
->PostTask(
87 base::Bind(&GamepadProvider::SendPauseHint
, Unretained(this), false));
88 polling_loop
->PostTask(
90 base::Bind(&GamepadProvider::ScheduleDoPoll
, Unretained(this)));
93 void GamepadProvider::RegisterForUserGesture(const base::Closure
& closure
) {
94 base::AutoLock
lock(user_gesture_lock_
);
95 user_gesture_observers_
.push_back(
96 ClosureAndThread(closure
, MessageLoop::current()->message_loop_proxy()));
99 void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type
) {
100 base::AutoLock
lock(devices_changed_lock_
);
101 devices_changed_
= true;
104 void GamepadProvider::Initialize(scoped_ptr
<GamepadDataFetcher
> fetcher
) {
105 size_t data_size
= sizeof(GamepadHardwareBuffer
);
106 base::SystemMonitor
* monitor
= base::SystemMonitor::Get();
108 monitor
->AddDevicesChangedObserver(this);
109 bool res
= gamepad_shared_memory_
.CreateAndMapAnonymous(data_size
);
111 GamepadHardwareBuffer
* hwbuf
= SharedMemoryAsHardwareBuffer();
112 memset(hwbuf
, 0, sizeof(GamepadHardwareBuffer
));
114 polling_thread_
.reset(new base::Thread("Gamepad polling thread"));
115 polling_thread_
->StartWithOptions(
116 base::Thread::Options(MessageLoop::TYPE_IO
, 0));
118 polling_thread_
->message_loop()->PostTask(
120 base::Bind(&GamepadProvider::DoInitializePollingThread
,
121 base::Unretained(this),
122 base::Passed(&fetcher
)));
125 void GamepadProvider::DoInitializePollingThread(
126 scoped_ptr
<GamepadDataFetcher
> fetcher
) {
127 DCHECK(MessageLoop::current() == polling_thread_
->message_loop());
128 DCHECK(!data_fetcher_
.get()); // Should only initialize once.
131 fetcher
.reset(new GamepadPlatformDataFetcher
);
132 data_fetcher_
= fetcher
.Pass();
135 void GamepadProvider::SendPauseHint(bool paused
) {
136 DCHECK(MessageLoop::current() == polling_thread_
->message_loop());
137 if (data_fetcher_
.get())
138 data_fetcher_
->PauseHint(paused
);
141 void GamepadProvider::DoPoll() {
142 DCHECK(MessageLoop::current() == polling_thread_
->message_loop());
143 DCHECK(have_scheduled_do_poll_
);
144 have_scheduled_do_poll_
= false;
147 GamepadHardwareBuffer
* hwbuf
= SharedMemoryAsHardwareBuffer();
149 ANNOTATE_BENIGN_RACE_SIZED(
151 sizeof(WebKit::WebGamepads
),
152 "Racey reads are discarded");
155 base::AutoLock
lock(devices_changed_lock_
);
156 changed
= devices_changed_
;
157 devices_changed_
= false;
160 // Acquire the SeqLock. There is only ever one writer to this data.
161 // See gamepad_hardware_buffer.h.
162 hwbuf
->sequence
.WriteBegin();
163 data_fetcher_
->GetGamepadData(&hwbuf
->buffer
, changed
);
164 hwbuf
->sequence
.WriteEnd();
166 CheckForUserGesture();
168 // Schedule our next interval of polling.
172 void GamepadProvider::ScheduleDoPoll() {
173 DCHECK(MessageLoop::current() == polling_thread_
->message_loop());
174 if (have_scheduled_do_poll_
)
178 base::AutoLock
lock(is_paused_lock_
);
183 MessageLoop::current()->PostDelayedTask(
185 base::Bind(&GamepadProvider::DoPoll
, Unretained(this)),
186 base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs
));
187 have_scheduled_do_poll_
= true;
190 GamepadHardwareBuffer
* GamepadProvider::SharedMemoryAsHardwareBuffer() {
191 void* mem
= gamepad_shared_memory_
.memory();
193 return static_cast<GamepadHardwareBuffer
*>(mem
);
196 void GamepadProvider::CheckForUserGesture() {
197 base::AutoLock
lock(user_gesture_lock_
);
198 if (user_gesture_observers_
.empty())
199 return; // Don't need to check if nobody is listening.
201 if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer
)) {
202 for (size_t i
= 0; i
< user_gesture_observers_
.size(); i
++) {
203 user_gesture_observers_
[i
].message_loop
->PostTask(FROM_HERE
,
204 user_gesture_observers_
[i
].closure
);
206 user_gesture_observers_
.clear();
210 } // namespace content