// 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 > 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()); 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 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(mem); } } // namespace content