Index: media/base/state_machine_driver.h |
diff --git a/media/base/state_machine_driver.h b/media/base/state_machine_driver.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..898a76883162b42446cf9f6d799b821c6cd36de3 |
--- /dev/null |
+++ b/media/base/state_machine_driver.h |
@@ -0,0 +1,100 @@ |
+// Copyright 2016 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. |
+ |
+#ifndef MEDIA_BASE_STATE_MACHINE_DRIVER_H_ |
+#define MEDIA_BASE_STATE_MACHINE_DRIVER_H_ |
+ |
+#include <unordered_set> |
+ |
+#include "base/memory/ref_counted.h" |
+#include "base/memory/weak_ptr.h" |
+#include "base/single_thread_task_runner.h" |
+#include "media/base/media_export.h" |
+#include "media/base/state_machine.h" |
+ |
+namespace media { |
+ |
+// Drives one or more state machines. |
+// Drivers own machines. machines own (shared) state. all machines in a driver |
+// are run on a single thread. if state is shared between machines on different |
+// drivers that also are on different threads, then i'm not sure. i guess that |
+// the state would have to know (task_runner, client) for each client and post |
+// if it's on the wrong one. plus, it would have to implement locking for its |
+// getters and setters. plus, it's unclear if state when state is allowed to |
+// change -- can it switch during a run of a machine? |
+// Also note that the driver doesn't need to own a new thread. |
+// For right now, it's better to think about everything on one thread. |
+class MEDIA_EXPORT StateMachineDriver : public StateMachine::Owner { |
+ public: |
+ StateMachineDriver(); |
+ virtual ~StateMachineDriver(); |
+ |
+ public: |
+ // Makes sure that |machine| will run, but not re-entrantly. Multiple calls |
+ // to this before it starts running are the same as one call. If |machine| is |
+ // currently running, or of some machine that this driver owns is running, |
+ // then it will not be run |machine| until later. |
+ // Note that it's unclear if this may run |machine| before it returns if no |
+ // machine that we own is running. If there are two variants, maybe only |
+ // one is part of the owner interface. We might expose a different call |
+ // that allows / requires |machine| to be run before it returns, |
+ // specifically to support cases like polling media codec. |
+ void RequestRun(StateMachine* machine) override; |
+ |
+ // Run |machine| immediately, before returning. |
+ // We might want a 'request run immediately before returning' that can be |
+ // used by something that's definitely not re-entrant, such as the timer |
+ // task that polls media codec. That timer task could be started / stopped |
+ // by state (e.g. 'last useful work time'), but that state would just have |
+ // some side-effects. Another example might be AVDA::Decode, or anything |
+ // else that calls DoIOTask() now. |
+ // Note that this does not guarantee that only |machine| will run, nor that |
+ // |machine| will run first. If you want that guarantee, then it's likely |
+ // that your state machine needs to be revised a bit. |
+ // TODO(liberato): should we just have 'RequestRun' and 'RunPendingMachines'? |
+ // We could, but RequestRun will try to post a task, since it doesn't know |
+ // that it should also run immediately. the post won't hurt, but it's a |
+ // waste of effort to do so. |
+ void RunImmediately(StateMachine* machine); |
+ |
+ // maybe NotifyMachinePending() to add to the running set, then RequestRun() |
+ // to run them at a steady state (post), or RunImmediately() to run them |
+ // before the call returns. that would let one add multiple machines to |
+ // the set before running them immediately, though i suppose one could call |
+ // RunImmediately multiple times. |
+ |
+ // Adds |machine| to our set of owned machines. We will run this when it |
+ // requests it, along with other machines. |
+ void AddStateMachine(std::unique_ptr<StateMachine> machine); |
+ |
+ protected: |
+ // Run by the posted task. Will run all machine in |machines_to_run_|, |
+ // and maybe more if that causes more to become ready. |
+ void RunTask(); |
+ |
+ private: |
+ // All the machines we own. |
+ std::unordered_set<std::unique_ptr<StateMachine>> machines_; |
+ |
+ // Set of machines that would like to run. Set by RequestRun. Must be a |
+ // subset of |machines_|. |
+ std::unordered_set<StateMachine*> machines_to_run_; |
+ |
+ // Set / cleared by RunAfterPost to indicate that RunAfterPost is running. |
+ bool currently_running_; |
+ |
+ // Set when a post to start the machine is pending. Cleared by RunAfterPost |
+ // when it runs. |
+ bool run_posted_; |
+ |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
+ |
+ base::WeakPtrFactory<StateMachineDriver> weak_factory_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(StateMachineDriver); |
+}; |
+ |
+} // namespace media |
+ |
+#endif // MEDIA_BASE_STATE_MACHINE_DRIVER_H_ |