• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 // Note: ported from Chromium commit head: 22d34680c8ac
5 
6 #include <v4l2_codec2/common/V4L2DevicePoller.h>
7 
8 #include <string>
9 
10 #include <base/bind.h>
11 #include <base/threading/sequenced_task_runner_handle.h>
12 #include <base/threading/thread_checker.h>
13 #include <log/log.h>
14 
15 #include <v4l2_codec2/common/V4L2Device.h>
16 
17 namespace android {
18 
V4L2DevicePoller(V4L2Device * const device,const std::string & threadName)19 V4L2DevicePoller::V4L2DevicePoller(V4L2Device* const device, const std::string& threadName)
20       : mDevice(device),
21         mPollThread(std::move(threadName)),
22         mTriggerPoll(base::WaitableEvent::ResetPolicy::AUTOMATIC,
23                      base::WaitableEvent::InitialState::NOT_SIGNALED),
24         mStopPolling(false) {}
25 
~V4L2DevicePoller()26 V4L2DevicePoller::~V4L2DevicePoller() {
27     ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
28 
29     stopPolling();
30 }
31 
startPolling(EventCallback eventCallback,base::RepeatingClosure errorCallback)32 bool V4L2DevicePoller::startPolling(EventCallback eventCallback,
33                                     base::RepeatingClosure errorCallback) {
34     if (isPolling()) return true;
35 
36     ALOGV("Starting polling");
37 
38     mClientTaskTunner = base::SequencedTaskRunnerHandle::Get();
39     mErrorCallback = errorCallback;
40 
41     if (!mPollThread.Start()) {
42         ALOGE("Failed to start device poll thread");
43         return false;
44     }
45 
46     mEventCallback = std::move(eventCallback);
47 
48     mStopPolling.store(false);
49     mPollThread.task_runner()->PostTask(
50             FROM_HERE, base::BindOnce(&V4L2DevicePoller::devicePollTask, base::Unretained(this)));
51 
52     ALOGV("Polling thread started");
53 
54     schedulePoll();
55 
56     return true;
57 }
58 
stopPolling()59 bool V4L2DevicePoller::stopPolling() {
60     ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
61 
62     if (!isPolling()) return true;
63 
64     ALOGV("Stopping polling");
65 
66     mStopPolling.store(true);
67 
68     mTriggerPoll.Signal();
69 
70     if (!mDevice->setDevicePollInterrupt()) {
71         ALOGE("Failed to interrupt device poll.");
72         return false;
73     }
74 
75     ALOGV("Stop device poll thread");
76     mPollThread.Stop();
77 
78     if (!mDevice->clearDevicePollInterrupt()) {
79         ALOGE("Failed to clear interrupting device poll.");
80         return false;
81     }
82 
83     ALOGV("Polling thread stopped");
84 
85     return true;
86 }
87 
isPolling() const88 bool V4L2DevicePoller::isPolling() const {
89     ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
90 
91     return mPollThread.IsRunning();
92 }
93 
schedulePoll()94 void V4L2DevicePoller::schedulePoll() {
95     ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
96 
97     // A call to DevicePollTask() will be posted when we actually start polling.
98     if (!isPolling()) return;
99 
100     ALOGV("Scheduling poll");
101 
102     mTriggerPoll.Signal();
103 }
104 
devicePollTask()105 void V4L2DevicePoller::devicePollTask() {
106     ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
107 
108     while (true) {
109         ALOGV("Waiting for poll to be scheduled.");
110         mTriggerPoll.Wait();
111 
112         if (mStopPolling) {
113             ALOGV("Poll stopped, exiting.");
114             break;
115         }
116 
117         bool event_pending = false;
118         ALOGV("Polling device.");
119         if (!mDevice->poll(true, &event_pending)) {
120             ALOGE("An error occurred while polling, calling error callback");
121             mClientTaskTunner->PostTask(FROM_HERE, mErrorCallback);
122             return;
123         }
124 
125         ALOGV("Poll returned, calling event callback.");
126         mClientTaskTunner->PostTask(FROM_HERE, base::Bind(mEventCallback, event_pending));
127     }
128 }
129 
130 }  // namespace android
131