1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96

media / gpu / v4l2 / v4l2_device_poller.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_V4L2_V4L2_DEVICE_POLLER_H_
#define MEDIA_GPU_V4L2_V4L2_DEVICE_POLLER_H_

#include <atomic>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/thread.h"

namespace media {

class V4L2Device;

// Allows a client to poll() on a given V4L2Device and be signaled when
// a buffer is ready to be dequeued or a V4L2 event has been received. Polling
// is done on a dedicated thread, and notifications are delivered in the form of
// a callback to the listener's sequence.
//
// All the methods of this class (with the exception of the constructor) must be
// called from the same sequence.
//
// Note that the service callback may also be called when no particular event
// occurred due to the way poll() works. It is the responsibility of the caller
// to call SchedulePoll() again if there may still be pending events.
class V4L2DevicePoller {
 public:
  // Callback to be called when buffer ready/V4L2 event has potentially been
  // polled. |event| is set if a V4L2 event has been detected.
  using EventCallback = base::RepeatingCallback<void(bool event)>;

  // Create a poller for |device|, using a thread named |thread_name|.
  // Notification won't start until |StartPolling()| is called.
  V4L2DevicePoller(V4L2Device* const device, const std::string& thread_name);
  ~V4L2DevicePoller();

  // Starts polling. |event_callback| will be posted on the caller's sequence
  // every time an event occurs. The client is then responsible for consuming
  // all pending events in that callback. If new events may still happen after
  // the callback has run, the client must call |SchedulePoll()| again in order
  // to be notified for them.
  //
  // If an error occurs during polling, |error_callback| will be posted on the
  // caller's sequence.
  bool StartPolling(EventCallback event_callback,
                    base::RepeatingClosure error_callback);
  // Stop polling and stop the thread. The poller won't post any new event to
  // the caller's sequence after this method has returned.
  bool StopPolling();
  // Returns true if currently polling, false otherwise.
  bool IsPolling() const;
  // Attempts polling the V4L2 device. This method should be called whenever
  // doing something that may trigger an event of interest (buffer dequeue or
  // V4L2 event), for instance queueing a buffer. In the absence of a pending
  // event, poll() will return immediately and the service callback will be
  // posted to the caller's sequence. The client is then responsible for calling
  // this method again when it is interested in receiving events.
  void SchedulePoll();

 private:
  // Perform a poll() on |device_| and post either |service_task_| or
  // |error_callback_| on the client's sequence when poll() returns.
  void DevicePollTask();

  // V4L2 device we are polling.
  raw_ptr<V4L2Device> const device_;
  // Thread on which polling is done.
  base::Thread poll_thread_;
  // Callback to post to the client's sequence when an event occurs.
  EventCallback event_callback_;
  // Closure to post to the client's sequence when an error occurs.
  base::RepeatingClosure error_callback_;
  // Client sequence's task runner, where closures are posted.
  scoped_refptr<base::SequencedTaskRunner> client_task_runner_;

  // Since poll() returns immediately if no buffers have been queued, we cannot
  // rely on it to pause the polling thread until an event occurs. Instead,
  // the polling thread will wait on this WaitableEvent (signaled by
  // |SchedulePoll| before calling poll(), so we only call it when we are
  // actually waiting for an event.
  base::WaitableEvent trigger_poll_;
  // Set to true when we wish to stop polling, instructing the poller thread
  // to break its loop.
  std::atomic_bool stop_polling_;

  SEQUENCE_CHECKER(client_sequence_checker_);
};

}  // namespace media

#endif  // MEDIA_GPU_V4L2_V4L2_DEVICE_POLLER_H_