Index: services/media/framework/engine.h |
diff --git a/services/media/framework/engine.h b/services/media/framework/engine.h |
index 2ceb0cff127237a0982c94a47c7daa46f5e393b8..55b5ae55a430ef48d6ef8f0a89b594be64782209 100644 |
--- a/services/media/framework/engine.h |
+++ b/services/media/framework/engine.h |
@@ -8,98 +8,19 @@ |
#include <list> |
#include <queue> |
#include <stack> |
+#include <unordered_map> |
#include "base/synchronization/lock.h" |
-#include "services/media/framework/stages/active_sink_stage.h" |
-#include "services/media/framework/stages/active_source_stage.h" |
-#include "services/media/framework/stages/distributor_stage.h" |
-#include "services/media/framework/stages/lpcm_transform_stage.h" |
-#include "services/media/framework/stages/packet_transform_stage.h" |
+#include "services/media/framework/refs.h" |
#include "services/media/framework/stages/stage.h" |
namespace mojo { |
namespace media { |
// |
-// USAGE |
-// |
-// TODO(dalesat): Consider adding a suffix to Engine::Part/Input/Output to |
-// indicate that they're references. |
-// TODO(dalesat): Consider folding PrimeSinks into Prepare. |
-// |
-// Engine is a container for sources, sinks and transforms ('parts') connected |
-// in a graph. Engine::Part, Engine::Input and Engine::Output are all opaque |
-// references to parts and their inputs and outputs. Engine provides a variety |
-// of methods for adding and removing parts and for connecting inputs and |
-// outputs to form a graph. |
-// |
-// In addition to containing parts and representing their interconnection, |
-// Engine manages the coordinated operation of its constituent parts and |
-// transports media from part to part. The Prepare method prepares the graph |
-// for operation, and the PrimeSinks method tells the sinks in the graph to |
-// prime themselves. Any additional actions required to make the graph operate |
-// (such as manipulating a rate control interface) is out of scope. |
-// |
-// Parts added to the engine are referenced using shared pointers. The engine |
-// holds pointers to the parts it contains, and the application, in many cases, |
-// also holds pointers to the parts so it can call methods that are outside the |
-// engine's scope. When a part is added the Engine returns an Engine::Part |
-// object, which can be used to reference the part when the graph is modified. |
-// Engine::Part objects can be interrogated to retrieve inputs (as Engine::Input |
-// objects) and outputs (as Engine::Output objects). |
-// |
-// Some support is provided for modifying graphs that are operating. This |
-// capability isn't fully developed at the moment. Prepare(Part) is an example |
-// of a method provided for this purpose. |
-// |
-// Parts come in various flavors, defined by 'model' abstract classes. The |
-// current list of supported models is: |
-// |
-// ActiveSink - a sink that consumes packets asynchronously |
-// ActiveSource - a source that produces packets asynchronously |
-// LpcmMixer - a transform that mixes LPCM frames from multiple |
-// inputs and produces a single stream of LPCM frames |
-// via one output |
-// LpcmSource - a source that produces LPCM frames synchronously |
-// LpcmTransform - a synchronous transform with one LPCM input and |
-// one LPCM output |
-// MultiStreamPacketSource - a source that produces multiple streams of packets |
-// synchronously |
-// PacketTransform - a synchronous transform that consumes and produces |
-// packets via one input and one output |
-// |
-// Other models will be defined in the future as needed. |
-// |
- |
-// |
// DESIGN |
// |
-// The Engine is implemented as a system of cooperating objects. Of those |
-// objects, only the engine itself is of relevance to code that uses Engine and |
-// to part implementations. The other objects are: |
-// |
-// Stage |
-// A stage hosts a single part. There are many subclasses of Stage, one for |
-// each supported part model. The stage's job is to implement the contract |
-// represented by the model so the parts that conform to the model can |
-// participate in the operation of the engine. Stages are uniform with respect |
-// to how they interact with engine. Engine::Part references a stage. |
-// |
-// StageInput |
-// A stage possesses zero or more StageInput instances. StageInput objects |
-// implement the supply of media into the stage and demand for media signalled |
-// upstream. StageInputs receive media from StageOutputs in the form of packets |
-// (type Packet). LpcmStageInput is a subclass of StageInput that interoperates |
-// with LpcmStageInputs in a way that provides optimizations relavant to LPCM |
-// audio media. Engine::Input references a StageInput. |
-// |
-// StageOutput |
-// A stage possesses zero or more StageOutput instances. StageOutput objects |
-// implement the supply of media output of the stage to a downstream input and |
-// demand for media signalled from that input. LpcmStageOutput implements |
-// optimized LPCM flow. Engine::Output references a StageOutput. |
-// |
-// Engine uses a 'work list' algorithm to operate the contained graph. The |
+// Engine uses a 'work list' algorithm to operate the graph. The |
// engine has a backlog of stages that need to be updated. To advance the |
// operation of the graph, the engine removes a stage from the backlog and calls |
// the stage's Update method. The Stage::Update may cause stages to be added |
@@ -143,7 +64,7 @@ namespace media { |
// supply and/or demand. |
// 3) Threads used to call update callbacks must be suitable for operating the |
// engine. There is currently no affordance for processing other tasks on |
-// a thread while the callback is running. A callback may run for a long |
+// the thread while the callback is running. A callback may run for a long |
// time, depending on how much work needs to be done. |
// 4) Parts cannot rely on being called back on the same thread on which they |
// invoke update callbacks. This may require additional synchronization and |
@@ -161,254 +82,64 @@ namespace media { |
// 2) Marshalling update callbacks to a different thread. |
// |
-// Host for a source, sink or transform. |
+// Manages operation of a Graph. |
class Engine { |
public: |
- class Input; |
- class Output; |
- |
- // Opaque Stage pointer used for graph building. |
- class Part { |
- public: |
- Part() : stage_(nullptr) {} |
- |
- uint32_t input_count(); |
- Input input(uint32_t index); |
- Input input(); |
- uint32_t output_count(); |
- Output output(uint32_t index); |
- Output output(); |
- Part upstream_part(uint32_t index); |
- Part upstream_part(); |
- Part downstream_part(uint32_t index); |
- Part downstream_part(); |
- |
- private: |
- explicit Part(Stage* stage) : stage_(stage) {} |
- |
- explicit operator bool() const { return stage_ != nullptr; } |
- |
- Stage* stage_; |
- |
- friend Engine; |
- friend Input; |
- friend Output; |
- }; |
- |
- // Opaque StageInput pointer used for graph building. |
- class Input { |
- public: |
- Input() : stage_(nullptr), index_(0) {} |
- |
- explicit operator bool() const { return stage_ != nullptr; } |
- |
- Part part() { return Part(stage_); } |
- |
- bool connected() { |
- DCHECK(stage_); |
- return stage_input().upstream_stage() != nullptr; |
- } |
- |
- Part upstream_part() { |
- DCHECK(connected()); |
- return Part(stage_input().upstream_stage()); |
- } |
- |
- private: |
- Input(Stage* stage, uint32_t index) : |
- stage_(stage), index_(index) { |
- DCHECK(stage_); |
- DCHECK(index_ < stage_->input_count()); |
- } |
- |
- StageInput& stage_input() { |
- DCHECK(stage_); |
- return stage_->input(index_); |
- } |
- |
- Stage* stage_; |
- uint32_t index_; |
- |
- friend Engine; |
- friend Part; |
- friend Output; |
- }; |
- |
- // Opaque StageOutput pointer used for graph building. |
- class Output { |
- public: |
- Output() : stage_(nullptr), index_(0) {} |
- |
- explicit operator bool() const { return stage_ != nullptr; } |
- |
- Part part() { return Part(stage_); } |
- |
- bool connected() { |
- DCHECK(stage_); |
- return stage_output().downstream_stage() != nullptr; |
- } |
- |
- Part downstream_part() { |
- DCHECK(connected()); |
- return Part(stage_output().downstream_stage()); |
- } |
- |
- private: |
- Output(Stage* stage, uint32_t index) : |
- stage_(stage), index_(index) { |
- DCHECK(stage_); |
- DCHECK(index_ < stage_->output_count()); |
- } |
- |
- StageOutput& stage_output() { |
- DCHECK(stage_); |
- return stage_->output(index_); |
- } |
- |
- Stage* stage_; |
- uint32_t index_; |
- |
- friend Engine; |
- friend Part; |
- friend Input; |
- }; |
- |
Engine(); |
~Engine(); |
- // Adds a part to the engine. |
- template<typename T, typename TBase> |
- Part Add(SharedPtr<T, TBase> t) { |
- DCHECK(t); |
- return Add(CreateStage(std::shared_ptr<TBase>(t))); |
- } |
- |
- // Removes a part from the engine after disconnecting it from other parts. |
- void RemovePart(Part part); |
- |
- // Connects an output connector to an input connector. Returns the dowstream |
- // part. |
- Part Connect(Output output, Input input); |
- |
- // Connects a part with exactly one output to a part with exactly one input. |
- // Returns the downstream part. |
- Part ConnectParts(Part upstream_part, Part downstream_part); |
+ // Prepares the input and the subgraph upstream of it. |
+ void PrepareInput(const InputRef& input_ref); |
- // Connects an output connector to a part that has exactly one input. Returns |
- // the downstream part. |
- Part ConnectOutputToPart(Output output, Part downstream_part); |
+ // Unprepares the input and the subgraph upstream of it. |
+ void UnprepareInput(const InputRef& input_ref); |
- // Connects a part with exactly one output to an input connector. Returns the |
- // downstream part. |
- Part ConnectPartToInput(Part upstream_part, Input input); |
+ // Flushes the output and the subgraph downstream of it. |
+ void FlushOutput(const OutputRef& output_ref); |
- // Disconnects an output connector and the input connector to which it's |
- // connected. |
- void DisconnectOutput(Output output); |
+ // Queues the stage for update and winds down the backlog. |
+ void RequestUpdate(Stage* stage); |
- // Disconnects an input connector and the output connector to which it's |
- // connected. |
- void DisconnectInput(Input input); |
- |
- // Disconnects and removes part and everything connected to it. |
- void RemovePartsConnectedToPart(Part part); |
- |
- // Disconnects and removes everything connected to output. |
- void RemovePartsConnectedToOutput(Output output); |
- |
- // Disconnects and removes everything connected to input. |
- void RemovePartsConnectedToInput(Input input); |
- |
- // Adds all the parts in t (which must all have one input and one output) and |
- // connects them in sequence to the output connector. Returns the output |
- // connector of the last part or the output parameter if it is empty. |
- template<typename T> |
- Output AddAndConnectAll( |
- Output output, |
- const T& t) { |
- for (auto& element : t) { |
- Part part = Add(CreateStage(element)); |
- Connect(output, part.input()); |
- output = part.output(); |
- } |
- return output; |
- } |
- |
- // Prepares the engine. |
- void Prepare(); |
- |
- // Prepares the part and everything upstream of it. This method is used to |
- // prepare subgraphs added when the rest of the graph is already prepared. |
- void Prepare(Part part); |
- |
- // Primes all the sinks in the graph. |
- void PrimeSinks(); |
+ // Pushes the stage to the supply backlog if it isn't already there. |
+ void PushToSupplyBacklog(Stage* stage); |
- // Removes all parts from the engine. |
- void Reset(); |
+ // Pushes the stage to the demand backlog if it isn't already there. |
+ void PushToDemandBacklog(Stage* stage); |
private: |
- // Adds a stage to the engine. |
- Part Add(Stage* stage); |
- |
- // Disconnects an output. |
- void DisconnectOutputUnsafe(Stage* stage, uint32_t index); |
- |
- // Disconnects an input. |
- void DisconnectInputUnsafe(Stage* stage, uint32_t index); |
- |
- // Removes a stage. |
- void RemoveUnsafe(Stage* stage); |
- |
- // Creates a stage from a source, sink or transform. A specialization of this |
- // template is defined for each type of source, sink or transform that can be |
- // added to the engine. |
- template<typename T> |
- static Stage* CreateStage(std::shared_ptr<T> t); |
- |
- // CreateStage template specialization for MultiStreamPacketSource. |
- static Stage* CreateStage(MultiStreamPacketSourcePtr source); |
- |
- // CreateStage template specialization for PacketTransform. |
- static Stage* CreateStage(PacketTransformPtr transform); |
- |
- // CreateStage template specialization for ActiveSource. |
- static Stage* CreateStage(ActiveSourcePtr source); |
- |
- // CreateStage template specialization for ActiveSink. |
- static Stage* CreateStage(ActiveSinkPtr sink); |
- |
- // CreateStage template specialization for LpcmTransform. |
- static Stage* CreateStage(LpcmTransformPtr transform); |
- |
- // Prepares a stage if all its downstream stages are prepared. |
- void MaybePrepareUnsafe(Stage* stage); |
+ using UpstreamVisitor = std::function<void( |
+ const InputRef& input, |
+ const OutputRef& output, |
+ const Stage::UpstreamCallback& callback)>; |
+ using DownstreamVisitor = std::function<void( |
+ const OutputRef& output, |
+ const InputRef& input, |
+ const Stage::DownstreamCallback& callback)>; |
+ |
+ void VisitUpstream( |
+ const InputRef& input, |
+ const UpstreamVisitor& vistor); |
+ |
+ void VisitDownstream( |
+ const OutputRef& output, |
+ const DownstreamVisitor& vistor); |
// Processes the entire backlog. |
- void UpdateUnsafe(); |
+ void Update(); |
// Performs processing for a single stage, updating the backlog accordingly. |
- void UpdateUnsafe(Stage *stage); |
- |
- // Pushes the stage to the supply backlog if it isn't already there. |
- void PushToSupplyBacklogUnsafe(Stage* stage); |
- |
- // Pushes the stage to the demand backlog if it isn't already there. |
- void PushToDemandBacklogUnsafe(Stage* stage); |
+ void Update(Stage *stage); |
// Pops a stage from the supply backlog and returns it or returns nullptr if |
// the supply backlog is empty. |
- Stage* PopFromSupplyBacklogUnsafe(); |
+ Stage* PopFromSupplyBacklog(); |
// Pops a stage from the demand backlog and returns it or returns nullptr if |
// the demand backlog is empty. |
- Stage* PopFromDemandBacklogUnsafe(); |
+ Stage* PopFromDemandBacklog(); |
mutable base::Lock lock_; |
- std::list<Stage*> stages_; |
- std::list<Stage*> sources_; |
- std::list<Stage*> sinks_; |
// supply_backlog_ contains pointers to all the stages that have been supplied |
// (packets or frames) but have not been updated since. demand_backlog_ does |
// the same for demand. The use of queue vs stack here is a guess as to what |
@@ -417,16 +148,10 @@ class Engine { |
// TODO(dalesat): Determine the best ordering and implement it. |
std::queue<Stage*> supply_backlog_; |
std::stack<Stage*> demand_backlog_; |
- Stage::UpdateCallback update_function_; |
bool packets_produced_; |
- |
- friend class StageInput; |
- friend class StageOutput; |
- friend class LpcmStageInput; |
- friend class LpcmStageOutput; |
}; |
} // namespace media |
} // namespace mojo |
-#endif // SERVICES_MEDIA_FRAMEWORK_ENGINE_ENGINE_H_ |
+#endif // SERVICES_MEDIA_FRAMEWORK_ENGINE_H_ |