blob: 0d89ebc9efbd517f249dc882e1741ef0f21de28b [file] [log] [blame]
// 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 SERVICES_MEDIA_FRAMEWORK_GRAPH_H_
#define SERVICES_MEDIA_FRAMEWORK_GRAPH_H_
#include <list>
#include "services/media/framework/engine.h"
#include "services/media/framework/refs.h"
#include "services/media/framework/stages/active_multistream_source_stage.h"
#include "services/media/framework/stages/active_sink_stage.h"
#include "services/media/framework/stages/active_source_stage.h"
#include "services/media/framework/stages/multistream_source_stage.h"
#include "services/media/framework/stages/stage.h"
#include "services/media/framework/stages/transform_stage.h"
namespace mojo {
namespace media {
namespace {
// StageCreator::Create creates a stage for a part. DEFINE_STAGE_CREATOR defines
// a specialization for a particular model/stage type pair. Every new
// model/stage type pair that's defined will need an entry here.
template <typename T, typename Enable = void>
class StageCreator;
#define DEFINE_STAGE_CREATOR(TModel, TStage) \
template <typename T> \
class StageCreator< \
T, typename std::enable_if<std::is_base_of<TModel, T>::value>::type> { \
public: \
static inline Stage* Create(std::shared_ptr<T> t_ptr) { \
return new TStage(std::shared_ptr<TModel>(t_ptr)); \
} \
};
DEFINE_STAGE_CREATOR(MultistreamSource, MultistreamSourceStage);
DEFINE_STAGE_CREATOR(Transform, TransformStage);
DEFINE_STAGE_CREATOR(ActiveSource, ActiveSourceStage);
DEFINE_STAGE_CREATOR(ActiveSink, ActiveSinkStage);
DEFINE_STAGE_CREATOR(ActiveMultistreamSource, ActiveMultistreamSourceStage);
#undef DEFINE_STAGE_CREATOR
} // namespace
//
// USAGE
//
// Graph is a container for sources, sinks and transforms ('parts') connected
// in a graph. PartRef, InputRef and OutputRef are all
// references to parts and their inputs and outputs. Graph provides a variety
// of methods for adding and removing parts and for connecting inputs and
// outputs to form a graph.
//
// The graph isn't thread-safe. If the graph is to be modified and/or
// interrogated on multiple threads, the caller must provide its own lock
// to prevent collisions. In this case, the caller must also acquire the same
// lock when making calls that cause parts to add or remove inputs or outputs.
//
// The graph prevents the disconnection of prepared inputs and outputs. Once
// a connected input/output pair is prepared, it must be unprepared before
// disconnection. This allows the engine to operate freely over prepared
// portions of the graph (prepare and unprepare are synchronized with the
// engine).
//
// Parts added to the graph are referenced using shared pointers. The graph
// 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
// graph's scope. When a part is added, the graph returns a PartRef
// object, which can be used to reference the part when the graph is modified.
// PartRef objects can be interrogated to retrieve inputs (as
// InputRef objects) and outputs (as OutputRef objects).
//
// 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
// MultistreamSource - a source that produces multiple streams of packets
// synchronously
// Transform - 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 Graph is implemented as a system of cooperating objects. Of those
// objects, only the graph itself is of relevance to code that uses Graph 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 graph. Stages are uniform with respect
// to how they interact with graph. PartRef references a stage.
//
// Input
// A stage possesses zero or more Input instances. Input objects
// implement the supply of media into the stage and demand for media signalled
// upstream. Inputs recieve media from Outputs in the form of packets
// (type Packet).
//
// Output
// A stage possesses zero or more Output instances. Output objects
// implement the supply of media output of the stage to a downstream input and
// demand for media signalled from that input.
//
// Host for a source, sink or transform.
class Graph {
public:
Graph();
~Graph();
// Adds a part to the graph.
template <typename T>
PartRef Add(std::shared_ptr<T> t_ptr) {
DCHECK(t_ptr);
return Add(StageCreator<T>::Create(t_ptr));
}
// Removes a part from the graph after disconnecting it from other parts.
void RemovePart(PartRef part);
// Connects an output connector to an input connector. Returns the dowstream
// part.
PartRef Connect(const OutputRef& output, const InputRef& input);
// Connects a part with exactly one output to a part with exactly one input.
// Returns the downstream part.
PartRef ConnectParts(PartRef upstream_part, PartRef downstream_part);
// Connects an output connector to a part that has exactly one input. Returns
// the downstream part.
PartRef ConnectOutputToPart(const OutputRef& output, PartRef downstream_part);
// Connects a part with exactly one output to an input connector. Returns the
// downstream part.
PartRef ConnectPartToInput(PartRef upstream_part, const InputRef& input);
// Disconnects an output connector and the input connector to which it's
// connected.
void DisconnectOutput(const OutputRef& output);
// Disconnects an input connector and the output connector to which it's
// connected.
void DisconnectInput(const InputRef& input);
// Disconnects and removes part and everything connected to it.
void RemovePartsConnectedToPart(PartRef part);
// Disconnects and removes everything connected to output.
void RemovePartsConnectedToOutput(const OutputRef& output);
// Disconnects and removes everything connected to input.
void RemovePartsConnectedToInput(const InputRef& 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>
OutputRef AddAndConnectAll(OutputRef output, const T& t) {
for (const auto& element : t) {
PartRef part = Add(StageCreator<T>::Create(element));
Connect(output, part.input());
output = part.output();
}
return output;
}
// Removes all parts from the graph.
void Reset();
// Prepares the graph for operation.
void Prepare();
// Prepares the input and everything upstream of it. This method is used to
// prepare subgraphs added when the rest of the graph is already prepared.
void PrepareInput(const InputRef& input);
// Flushes the output and the subgraph downstream of it.
void FlushOutput(const OutputRef& output);
// Flushes the output and the subgraph downstream of it.
void FlushAllOutputs(PartRef part);
private:
// Adds a stage to the graph.
PartRef Add(Stage* stage);
std::list<Stage*> stages_;
std::list<Stage*> sources_;
std::list<Stage*> sinks_;
Engine engine_;
Stage::UpdateCallback update_function_;
};
} // namespace media
} // namespace mojo
#endif // SERVICES_MEDIA_FRAMEWORK_GRAPH_H_