1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_GraphRunner_h
8 #define mozilla_GraphRunner_h
9 
10 #include "GraphDriver.h"
11 #include "MediaSegment.h"
12 #include "mozilla/Monitor.h"
13 
14 #include <thread>
15 
16 struct PRThread;
17 
18 namespace mozilla {
19 
20 class AudioMixer;
21 class MediaTrackGraphImpl;
22 
23 class GraphRunner final : public Runnable {
24   using IterationResult = GraphInterface::IterationResult;
25 
26  public:
27   static already_AddRefed<GraphRunner> Create(MediaTrackGraphImpl* aGraph);
28 
29   /**
30    * Marks us as shut down and signals mThread, so that it runs until the end.
31    */
32   MOZ_CAN_RUN_SCRIPT void Shutdown();
33 
34   /**
35    * Signals one iteration of mGraph. Hands state over to mThread and runs
36    * the iteration there.
37    */
38   IterationResult OneIteration(GraphTime aStateTime, GraphTime aIterationEnd,
39                                AudioMixer* aMixer);
40 
41   /**
42    * Runs mGraph until it shuts down.
43    */
44   NS_IMETHOD Run();
45 
46   /**
47    * Returns true if called on mThread.
48    */
49   bool OnThread() const;
50 
51 #ifdef DEBUG
52   /**
53    * Returns true if called on mThread, and aDriver was the driver that called
54    * OneIteration() last.
55    */
56   bool InDriverIteration(const GraphDriver* aDriver) const;
57 #endif
58 
59  private:
60   explicit GraphRunner(MediaTrackGraphImpl* aGraph,
61                        already_AddRefed<nsIThread> aThread);
62   ~GraphRunner();
63 
64   class IterationState {
65     GraphTime mStateTime;
66     GraphTime mIterationEnd;
67     AudioMixer* MOZ_NON_OWNING_REF mMixer;
68 
69    public:
IterationState(GraphTime aStateTime,GraphTime aIterationEnd,AudioMixer * aMixer)70     IterationState(GraphTime aStateTime, GraphTime aIterationEnd,
71                    AudioMixer* aMixer)
72         : mStateTime(aStateTime),
73           mIterationEnd(aIterationEnd),
74           mMixer(aMixer) {}
75     IterationState& operator=(const IterationState& aOther) = default;
StateTime()76     GraphTime StateTime() const { return mStateTime; }
IterationEnd()77     GraphTime IterationEnd() const { return mIterationEnd; }
Mixer()78     AudioMixer* Mixer() const { return mMixer; }
79   };
80 
81   // Monitor used for yielding mThread through Wait(), and scheduling mThread
82   // through Signal() from a GraphDriver.
83   Monitor mMonitor;
84   // The MediaTrackGraph we're running. Weakptr beecause this graph owns us and
85   // guarantees that our lifetime will not go beyond that of itself.
86   MediaTrackGraphImpl* const mGraph;
87   // State being handed over to the graph through OneIteration. Protected by
88   // mMonitor.
89   Maybe<IterationState> mIterationState;
90   // Result from mGraph's OneIteration. Protected by mMonitor.
91   IterationResult mIterationResult;
92 
93   enum class ThreadState {
94     Wait,      // Waiting for a message.  This is the initial state.
95                // A transition from Run back to Wait occurs on the runner thread
96                // after it processes as far as mIterationState->mStateTime
97                // and sets mIterationResult.
98     Run,       // Set on driver thread after each mIterationState update.
99     Shutdown,  // Set when Shutdown() is called on main thread.
100   };
101   // Protected by mMonitor until set to Shutdown, after which this is not
102   // modified.
103   ThreadState mThreadState;
104 
105   // The thread running mGraph.  Set on construction, after other members are
106   // initialized.  Cleared at the end of Shutdown().
107   const nsCOMPtr<nsIThread> mThread;
108 
109 #ifdef DEBUG
110   // Set to mGraph's audio callback driver's thread id, if run by an
111   // AudioCallbackDriver, while OneIteration() is running.
112   std::thread::id mAudioDriverThreadId = std::thread::id();
113   // Set to mGraph's system clock driver's thread, if run by a
114   // SystemClockDriver, while OneIteration() is running.
115   nsIThread* mClockDriverThread = nullptr;
116 #endif
117 };
118 
119 }  // namespace mozilla
120 
121 #endif
122