You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.4 KiB
131 lines
3.4 KiB
// Copyright 2019 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.
|
|
// Note: ported from Chromium commit head: 22d34680c8ac
|
|
|
|
#include <v4l2_codec2/common/V4L2DevicePoller.h>
|
|
|
|
#include <string>
|
|
|
|
#include <base/bind.h>
|
|
#include <base/threading/sequenced_task_runner_handle.h>
|
|
#include <base/threading/thread_checker.h>
|
|
#include <log/log.h>
|
|
|
|
#include <v4l2_codec2/common/V4L2Device.h>
|
|
|
|
namespace android {
|
|
|
|
V4L2DevicePoller::V4L2DevicePoller(V4L2Device* const device, const std::string& threadName)
|
|
: mDevice(device),
|
|
mPollThread(std::move(threadName)),
|
|
mTriggerPoll(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
|
base::WaitableEvent::InitialState::NOT_SIGNALED),
|
|
mStopPolling(false) {}
|
|
|
|
V4L2DevicePoller::~V4L2DevicePoller() {
|
|
ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
|
|
|
|
stopPolling();
|
|
}
|
|
|
|
bool V4L2DevicePoller::startPolling(EventCallback eventCallback,
|
|
base::RepeatingClosure errorCallback) {
|
|
if (isPolling()) return true;
|
|
|
|
ALOGV("Starting polling");
|
|
|
|
mClientTaskTunner = base::SequencedTaskRunnerHandle::Get();
|
|
mErrorCallback = errorCallback;
|
|
|
|
if (!mPollThread.Start()) {
|
|
ALOGE("Failed to start device poll thread");
|
|
return false;
|
|
}
|
|
|
|
mEventCallback = std::move(eventCallback);
|
|
|
|
mStopPolling.store(false);
|
|
mPollThread.task_runner()->PostTask(
|
|
FROM_HERE, base::BindOnce(&V4L2DevicePoller::devicePollTask, base::Unretained(this)));
|
|
|
|
ALOGV("Polling thread started");
|
|
|
|
schedulePoll();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool V4L2DevicePoller::stopPolling() {
|
|
ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
|
|
|
|
if (!isPolling()) return true;
|
|
|
|
ALOGV("Stopping polling");
|
|
|
|
mStopPolling.store(true);
|
|
|
|
mTriggerPoll.Signal();
|
|
|
|
if (!mDevice->setDevicePollInterrupt()) {
|
|
ALOGE("Failed to interrupt device poll.");
|
|
return false;
|
|
}
|
|
|
|
ALOGV("Stop device poll thread");
|
|
mPollThread.Stop();
|
|
|
|
if (!mDevice->clearDevicePollInterrupt()) {
|
|
ALOGE("Failed to clear interrupting device poll.");
|
|
return false;
|
|
}
|
|
|
|
ALOGV("Polling thread stopped");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool V4L2DevicePoller::isPolling() const {
|
|
ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
|
|
|
|
return mPollThread.IsRunning();
|
|
}
|
|
|
|
void V4L2DevicePoller::schedulePoll() {
|
|
ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
|
|
|
|
// A call to DevicePollTask() will be posted when we actually start polling.
|
|
if (!isPolling()) return;
|
|
|
|
ALOGV("Scheduling poll");
|
|
|
|
mTriggerPoll.Signal();
|
|
}
|
|
|
|
void V4L2DevicePoller::devicePollTask() {
|
|
ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
|
|
|
|
while (true) {
|
|
ALOGV("Waiting for poll to be scheduled.");
|
|
mTriggerPoll.Wait();
|
|
|
|
if (mStopPolling) {
|
|
ALOGV("Poll stopped, exiting.");
|
|
break;
|
|
}
|
|
|
|
bool event_pending = false;
|
|
ALOGV("Polling device.");
|
|
if (!mDevice->poll(true, &event_pending)) {
|
|
ALOGE("An error occurred while polling, calling error callback");
|
|
mClientTaskTunner->PostTask(FROM_HERE, mErrorCallback);
|
|
return;
|
|
}
|
|
|
|
ALOGV("Poll returned, calling event callback.");
|
|
mClientTaskTunner->PostTask(FROM_HERE, base::Bind(mEventCallback, event_pending));
|
|
}
|
|
}
|
|
|
|
} // namespace android
|