• 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_device_poller.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 
14 #include "macros.h"
15 #include "v4l2_device.h"
16 
17 namespace media {
18 
V4L2DevicePoller(V4L2Device * const device,const std::string & thread_name)19 V4L2DevicePoller::V4L2DevicePoller(V4L2Device* const device,
20                                    const std::string& thread_name)
21     : device_(device),
22       poll_thread_(std::move(thread_name)),
23       trigger_poll_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
24                     base::WaitableEvent::InitialState::NOT_SIGNALED),
25       stop_polling_(false) {
26   DETACH_FROM_SEQUENCE(client_sequence_checker_);
27 }
28 
~V4L2DevicePoller()29 V4L2DevicePoller::~V4L2DevicePoller() {
30   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
31 
32   StopPolling();
33 }
34 
StartPolling(EventCallback event_callback,base::RepeatingClosure error_callback)35 bool V4L2DevicePoller::StartPolling(EventCallback event_callback,
36                                     base::RepeatingClosure error_callback) {
37   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
38 
39   if (IsPolling())
40     return true;
41 
42   DVLOGF(4) << "Starting polling";
43 
44   client_task_runner_ = base::SequencedTaskRunnerHandle::Get();
45   error_callback_ = error_callback;
46 
47   if (!poll_thread_.Start()) {
48     VLOGF(1) << "Failed to start device poll thread";
49     return false;
50   }
51 
52   event_callback_ = std::move(event_callback);
53 
54   stop_polling_.store(false);
55   poll_thread_.task_runner()->PostTask(
56       FROM_HERE, base::BindOnce(&V4L2DevicePoller::DevicePollTask,
57                                 base::Unretained(this)));
58 
59   DVLOGF(3) << "Polling thread started";
60 
61   SchedulePoll();
62 
63   return true;
64 }
65 
StopPolling()66 bool V4L2DevicePoller::StopPolling() {
67   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
68 
69   if (!IsPolling())
70     return true;
71 
72   DVLOGF(4) << "Stopping polling";
73 
74   stop_polling_.store(true);
75 
76   trigger_poll_.Signal();
77 
78   if (!device_->SetDevicePollInterrupt()) {
79     VLOGF(1) << "Failed to interrupt device poll.";
80     return false;
81   }
82 
83   DVLOGF(3) << "Stop device poll thread";
84   poll_thread_.Stop();
85 
86   if (!device_->ClearDevicePollInterrupt()) {
87     VLOGF(1) << "Failed to clear interrupting device poll.";
88     return false;
89   }
90 
91   DVLOGF(4) << "Polling thread stopped";
92 
93   return true;
94 }
95 
IsPolling() const96 bool V4L2DevicePoller::IsPolling() const {
97   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
98 
99   return poll_thread_.IsRunning();
100 }
101 
SchedulePoll()102 void V4L2DevicePoller::SchedulePoll() {
103   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
104 
105   // A call to DevicePollTask() will be posted when we actually start polling.
106   if (!IsPolling())
107     return;
108 
109   DVLOGF(4) << "Scheduling poll";
110 
111   trigger_poll_.Signal();
112 }
113 
DevicePollTask()114 void V4L2DevicePoller::DevicePollTask() {
115   DCHECK(poll_thread_.task_runner()->RunsTasksInCurrentSequence());
116 
117   while (true) {
118     DVLOGF(4) << "Waiting for poll to be scheduled.";
119     trigger_poll_.Wait();
120 
121     if (stop_polling_) {
122       DVLOGF(4) << "Poll stopped, exiting.";
123       break;
124     }
125 
126     bool event_pending = false;
127     DVLOGF(4) << "Polling device.";
128     if (!device_->Poll(true, &event_pending)) {
129       VLOGF(1) << "An error occurred while polling, calling error callback";
130       client_task_runner_->PostTask(FROM_HERE, error_callback_);
131       return;
132     }
133 
134     DVLOGF(4) << "Poll returned, calling event callback.";
135     client_task_runner_->PostTask(FROM_HERE,
136                                   base::Bind(event_callback_, event_pending));
137   }
138 }
139 
140 }  // namespace media
141