Home | History | Annotate | Download | only in device_orientation
      1 // Copyright 2013 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/device_orientation/device_motion_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/threading/thread.h"
     10 #include "base/timer/timer.h"
     11 #include "content/browser/device_orientation/data_fetcher_shared_memory.h"
     12 #include "content/common/device_motion_hardware_buffer.h"
     13 
     14 namespace content {
     15 
     16 namespace {
     17 const int kPeriodInMilliseconds = 100;
     18 }
     19 
     20 class DeviceMotionProvider::PollingThread : public base::Thread {
     21  public:
     22   explicit PollingThread(const char* name);
     23   virtual ~PollingThread();
     24 
     25   void StartPolling(DataFetcherSharedMemory* fetcher,
     26                     DeviceMotionHardwareBuffer* buffer);
     27   void StopPolling();
     28 
     29  private:
     30   void DoPoll();
     31 
     32   scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
     33   DataFetcherSharedMemory* fetcher_;
     34 
     35   DISALLOW_COPY_AND_ASSIGN(PollingThread);
     36 };
     37 
     38 // ---- PollingThread methods
     39 
     40 DeviceMotionProvider::PollingThread::PollingThread(const char* name)
     41     : base::Thread(name) {
     42 }
     43 
     44 DeviceMotionProvider::PollingThread::~PollingThread() {
     45 }
     46 
     47 void DeviceMotionProvider::PollingThread::StartPolling(
     48     DataFetcherSharedMemory* fetcher, DeviceMotionHardwareBuffer* buffer) {
     49   DCHECK(base::MessageLoop::current() == message_loop());
     50   DCHECK(!timer_);
     51 
     52   fetcher_ = fetcher;
     53   fetcher_->StartFetchingDeviceMotionData(buffer);
     54   timer_.reset(new base::RepeatingTimer<PollingThread>());
     55   timer_->Start(FROM_HERE,
     56                 base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds),
     57                 this, &PollingThread::DoPoll);
     58 }
     59 
     60 void DeviceMotionProvider::PollingThread::StopPolling() {
     61   DCHECK(base::MessageLoop::current() == message_loop());
     62   DCHECK(fetcher_);
     63   // this will also stop the timer before killing it.
     64   timer_.reset();
     65   fetcher_->StopFetchingDeviceMotionData();
     66 }
     67 
     68 void DeviceMotionProvider::PollingThread::DoPoll() {
     69   DCHECK(base::MessageLoop::current() == message_loop());
     70   fetcher_->FetchDeviceMotionDataIntoBuffer();
     71 }
     72 
     73 // ---- end PollingThread methods
     74 
     75 DeviceMotionProvider::DeviceMotionProvider()
     76     : is_started_(false) {
     77   Initialize();
     78 }
     79 
     80 DeviceMotionProvider::DeviceMotionProvider(
     81     scoped_ptr<DataFetcherSharedMemory> fetcher)
     82     : is_started_(false) {
     83   data_fetcher_ = fetcher.Pass();
     84   Initialize();
     85 }
     86 
     87 DeviceMotionProvider::~DeviceMotionProvider() {
     88   StopFetchingDeviceMotionData();
     89   // make sure polling thread stops before data_fetcher_ gets deleted.
     90   if (polling_thread_)
     91     polling_thread_->Stop();
     92   data_fetcher_.reset();
     93 }
     94 
     95 void DeviceMotionProvider::Initialize() {
     96   size_t data_size = sizeof(DeviceMotionHardwareBuffer);
     97   bool res = device_motion_shared_memory_.CreateAndMapAnonymous(data_size);
     98   // TODO(timvolodine): consider not crashing the browser if the check fails.
     99   CHECK(res);
    100   DeviceMotionHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
    101   memset(hwbuf, 0, sizeof(DeviceMotionHardwareBuffer));
    102 }
    103 
    104 base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess(
    105     base::ProcessHandle process) {
    106   base::SharedMemoryHandle renderer_handle;
    107   device_motion_shared_memory_.ShareToProcess(process, &renderer_handle);
    108   return renderer_handle;
    109 }
    110 
    111 void DeviceMotionProvider::StartFetchingDeviceMotionData() {
    112   if (is_started_)
    113     return;
    114 
    115   if (!data_fetcher_)
    116     data_fetcher_.reset(new DataFetcherSharedMemory);
    117 
    118   if (data_fetcher_->NeedsPolling()) {
    119     if (!polling_thread_)
    120         CreateAndStartPollingThread();
    121 
    122     polling_thread_->message_loop()->PostTask(
    123         FROM_HERE,
    124         base::Bind(&PollingThread::StartPolling,
    125                    base::Unretained(polling_thread_.get()),
    126                    data_fetcher_.get(),
    127                    SharedMemoryAsHardwareBuffer()));
    128   } else {
    129     data_fetcher_->StartFetchingDeviceMotionData(
    130         SharedMemoryAsHardwareBuffer());
    131   }
    132 
    133   is_started_ = true;
    134 }
    135 
    136 void DeviceMotionProvider::CreateAndStartPollingThread() {
    137   polling_thread_.reset(
    138       new PollingThread("Device Motion poller"));
    139 
    140   if (!polling_thread_->Start()) {
    141       LOG(ERROR) << "Failed to start Device Motion data polling thread";
    142       return;
    143   }
    144 }
    145 
    146 void DeviceMotionProvider::StopFetchingDeviceMotionData() {
    147   if (!is_started_)
    148     return;
    149 
    150   DCHECK(data_fetcher_);
    151 
    152   if (data_fetcher_->NeedsPolling()) {
    153     DCHECK(polling_thread_);
    154     polling_thread_->message_loop()->PostTask(
    155         FROM_HERE,
    156         base::Bind(&PollingThread::StopPolling,
    157                    base::Unretained(polling_thread_.get())));
    158   } else {
    159     data_fetcher_->StopFetchingDeviceMotionData();
    160   }
    161 
    162   is_started_ = false;
    163 }
    164 
    165 DeviceMotionHardwareBuffer*
    166 DeviceMotionProvider::SharedMemoryAsHardwareBuffer() {
    167   void* mem = device_motion_shared_memory_.memory();
    168   CHECK(mem);
    169   return static_cast<DeviceMotionHardwareBuffer*>(mem);
    170 }
    171 
    172 }  // namespace content
    173