blob: e88d5af83f4173e97fe97aaa3077ac828de702c9 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/device_orientation/device_motion_provider.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread.h"
#include "base/timer/timer.h"
#include "content/browser/device_orientation/data_fetcher_shared_memory.h"
#include "content/common/device_motion_hardware_buffer.h"
namespace content {
namespace {
const int kPeriodInMilliseconds = 100;
}
class DeviceMotionProvider::PollingThread : public base::Thread {
public:
explicit PollingThread(const char* name);
virtual ~PollingThread();
void StartPolling(DataFetcherSharedMemory* fetcher,
DeviceMotionHardwareBuffer* buffer);
void StopPolling();
private:
void DoPoll();
scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
DataFetcherSharedMemory* fetcher_;
DISALLOW_COPY_AND_ASSIGN(PollingThread);
};
// ---- PollingThread methods
DeviceMotionProvider::PollingThread::PollingThread(const char* name)
: base::Thread(name) {
}
DeviceMotionProvider::PollingThread::~PollingThread() {
}
void DeviceMotionProvider::PollingThread::StartPolling(
DataFetcherSharedMemory* fetcher, DeviceMotionHardwareBuffer* buffer) {
DCHECK(base::MessageLoop::current() == message_loop());
DCHECK(!timer_);
fetcher_ = fetcher;
fetcher_->StartFetchingDeviceMotionData(buffer);
timer_.reset(new base::RepeatingTimer<PollingThread>());
timer_->Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds),
this, &PollingThread::DoPoll);
}
void DeviceMotionProvider::PollingThread::StopPolling() {
DCHECK(base::MessageLoop::current() == message_loop());
DCHECK(fetcher_);
// this will also stop the timer before killing it.
timer_.reset();
fetcher_->StopFetchingDeviceMotionData();
}
void DeviceMotionProvider::PollingThread::DoPoll() {
DCHECK(base::MessageLoop::current() == message_loop());
fetcher_->FetchDeviceMotionDataIntoBuffer();
}
// ---- end PollingThread methods
DeviceMotionProvider::DeviceMotionProvider()
: is_started_(false) {
Initialize();
}
DeviceMotionProvider::DeviceMotionProvider(
scoped_ptr<DataFetcherSharedMemory> fetcher)
: is_started_(false) {
data_fetcher_ = fetcher.Pass();
Initialize();
}
DeviceMotionProvider::~DeviceMotionProvider() {
StopFetchingDeviceMotionData();
// make sure polling thread stops before data_fetcher_ gets deleted.
if (polling_thread_)
polling_thread_->Stop();
data_fetcher_.reset();
}
void DeviceMotionProvider::Initialize() {
size_t data_size = sizeof(DeviceMotionHardwareBuffer);
bool res = device_motion_shared_memory_.CreateAndMapAnonymous(data_size);
// TODO(timvolodine): consider not crashing the browser if the check fails.
CHECK(res);
DeviceMotionHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
memset(hwbuf, 0, sizeof(DeviceMotionHardwareBuffer));
}
base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess(
base::ProcessHandle process) {
base::SharedMemoryHandle renderer_handle;
device_motion_shared_memory_.ShareToProcess(process, &renderer_handle);
return renderer_handle;
}
void DeviceMotionProvider::StartFetchingDeviceMotionData() {
if (is_started_)
return;
if (!data_fetcher_)
data_fetcher_.reset(new DataFetcherSharedMemory);
if (data_fetcher_->NeedsPolling()) {
if (!polling_thread_)
CreateAndStartPollingThread();
polling_thread_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PollingThread::StartPolling,
base::Unretained(polling_thread_.get()),
data_fetcher_.get(),
SharedMemoryAsHardwareBuffer()));
} else {
data_fetcher_->StartFetchingDeviceMotionData(
SharedMemoryAsHardwareBuffer());
}
is_started_ = true;
}
void DeviceMotionProvider::CreateAndStartPollingThread() {
polling_thread_.reset(
new PollingThread("Device Motion poller"));
if (!polling_thread_->Start()) {
LOG(ERROR) << "Failed to start Device Motion data polling thread";
return;
}
}
void DeviceMotionProvider::StopFetchingDeviceMotionData() {
if (!is_started_)
return;
DCHECK(data_fetcher_);
if (data_fetcher_->NeedsPolling()) {
DCHECK(polling_thread_);
polling_thread_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PollingThread::StopPolling,
base::Unretained(polling_thread_.get())));
} else {
data_fetcher_->StopFetchingDeviceMotionData();
}
is_started_ = false;
}
DeviceMotionHardwareBuffer*
DeviceMotionProvider::SharedMemoryAsHardwareBuffer() {
void* mem = device_motion_shared_memory_.memory();
CHECK(mem);
return static_cast<DeviceMotionHardwareBuffer*>(mem);
}
} // namespace content