1/*
2Copyright 2018 Google Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS-IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef RESONANCE_AUDIO_NODE_NODE_H_
18#define RESONANCE_AUDIO_NODE_NODE_H_
19
20#include <memory>
21#include <set>
22#include <unordered_map>
23#include <utility>
24#include <vector>
25
26#include "base/logging.h"
27
28namespace vraudio {
29
30// Implements a processing node in a synchronous processing graph.
31// This processing graph is expected to be directed, acyclic, and
32// accessed from a single thread.
33//
34// Subclasses are expected to implement Process(), which will read
35// from all of the instance's inputs, process the data as necessary,
36// and then write to all of its outputs.
37//
38// Data is passed through unique_ptrs, so nodes are expected to
39// modify data in place whenever it suits their purposes. If an
40// outputs is connected to more than one input, copies will be made for
41// each input.
42//
43// Graphs are managed through shared_ptrs. Orphaned nodes are kept
44// alive as long as they output to a living input. Ownership is
45// unidirectional -- from input to output -- in order to avoid
46// circular dependencies.
47class Node : public std::enable_shared_from_this<Node> {
48 public:
49 virtual ~Node() {}
50 virtual void Process() = 0;
51
52 // Disconnects from input nodes that are marked to be at the end of data
53 // stream.
54 //
55 // @return True if node is does not have any inputs and can be removed, false
56 // otherwise.
57 virtual bool CleanUp() = 0;
58
59 template <class T>
60 class Output;
61
62 // An endpoint for a node, this object consumes data from any connected
63 // outputs. Because an input may be connected to more than one output, it
64 // returns a vector of read data. All outputs must be of the same type.
65 template <typename T>
66 class Input {
67 public:
68 // Unordered map that stores pairs of input Node instances and their
69 // |Output| member.
70 typedef std::unordered_map<Output<T>*, std::shared_ptr<Node>> OutputNodeMap;
71
72 Input() {}
73 ~Input();
74
75 // Returns a vector of computed data, one for each connected output.
76 const std::vector<T>& Read();
77
78 // Connects this input to the specified output.
79 //
80 // @param node The parent of the output.
81 // @param output The output to connect to.
82 void Connect(const std::shared_ptr<Node>& node, Output<T>* output);
83
84 // Disconnects this input from the specified output.
85 //
86 // @param output The output to be disconnected.
87 void Disconnect(Output<T>* output);
88
89 // Returns the number of connected outputs.
90 //
91 // @return Number of connected outputs.
92 size_t GetNumConnections() const;
93
94 // Returns reference to OutputNodeMap map to obtain all connected nodes and
95 // their outputs.
96 const OutputNodeMap& GetConnectedNodeOutputPairs();
97
98 // Disable copy constructor.
99 Input(const Input& that) = delete;
100
101 private:
102 friend class Node::Output<T>;
103
104 void AddOutput(const std::shared_ptr<Node>& node, Output<T>* output);
105 void RemoveOutput(Output<T>* output);
106
107 OutputNodeMap outputs_;
108 std::vector<T> read_data_;
109 };
110
111 // An endpoint for a node, this object produces data for any connected inputs.
112 // Because an output may have more than one input, this object will duplicate
113 // any computed data, once for each connected input. All inputs must be of the
114 // same type.
115 //
116 // If an output does not have any data to deliver, it will ask its parent node
117 // to process more data. It is assumed that after processing, some new data
118 // will be written to this output.
119 template <typename T>
120 class Output {
121 public:
122 explicit Output(Node* node) : parent_(node) {}
123
124 // Parent nodes should call this function to push new data to any connected
125 // inputs. This data will be copied once for each connected input.
126 //
127 // @param data New data to pass to all connected inputs.
128 void Write(T data);
129
130 // Disable copy constructor.
131 Output(const Output& that) = delete;
132
133 private:
134 friend class Node::Input<T>;
135
136 // Signature of copy operator.
137 typedef T (*CopyOperator)(const T&);
138
139 // Returns a single piece of stored processed data. If no data exists,
140 // the parent node is processed to produce more data.
141 T PullData();
142
143 void AddInput(Input<T>* input);
144 bool RemoveInput(Input<T>* input);
145
146 std::set<Input<T>*> inputs_;
147 std::vector<T> written_data_;
148 Node* parent_;
149 };
150};
151
152template <class T>
153Node::Input<T>::~Input() {
154 for (auto& o : outputs_) {
155 CHECK(o.first->RemoveInput(this));
156 }
157}
158
159template <class T>
160const std::vector<T>& Node::Input<T>::Read() {
161 read_data_.clear();
162
163 for (auto& o : outputs_) {
164 // Obtain processed data.
165 T processed_data = o.first->PullData();
166 if (processed_data != nullptr) {
167 read_data_.emplace_back(std::move(processed_data));
168 }
169 }
170
171 return read_data_;
172}
173
174template <class T>
175void Node::Input<T>::Connect(const std::shared_ptr<Node>& node,
176 Output<T>* output) {
177 output->AddInput(this);
178 AddOutput(node, output);
179}
180
181// RemoveOutput(output) may trigger *output be destructed,
182// so we need to call output->RemoveInput(this) first.
183template <class T>
184void Node::Input<T>::Disconnect(Output<T>* output) {
185 output->RemoveInput(this);
186 RemoveOutput(output);
187}
188
189template <class T>
190size_t Node::Input<T>::GetNumConnections() const {
191 return outputs_.size();
192}
193
194template <class T>
195const typename Node::Input<T>::OutputNodeMap&
196Node::Input<T>::GetConnectedNodeOutputPairs() {
197 return outputs_;
198}
199
200template <class T>
201void Node::Input<T>::AddOutput(const std::shared_ptr<Node>& node,
202 Output<T>* output) {
203 outputs_[output] = node;
204
205 DCHECK(outputs_.find(output) != outputs_.end());
206}
207
208template <class T>
209void Node::Input<T>::RemoveOutput(Output<T>* output) {
210 outputs_.erase(output);
211}
212
213template <class T>
214T Node::Output<T>::PullData() {
215 if (written_data_.empty()) {
216 parent_->Process();
217 }
218
219 DCHECK(!written_data_.empty());
220
221 T return_value = std::move(written_data_.back());
222 written_data_.pop_back();
223 return return_value;
224}
225
226template <class T>
227void Node::Output<T>::Write(T data) {
228 DCHECK(written_data_.empty());
229 written_data_.clear();
230 written_data_.emplace_back(std::move(data));
231
232 // If we have more than one connected input, copy the data for each input.
233 for (size_t i = 1; i < inputs_.size(); i++) {
234 written_data_.push_back(written_data_[0]);
235 }
236
237 DCHECK(written_data_.size() == inputs_.size());
238}
239
240template <class T>
241void Node::Output<T>::AddInput(Input<T>* input) {
242 inputs_.insert(input);
243}
244
245template <class T>
246bool Node::Output<T>::RemoveInput(Input<T>* input) {
247 auto it = inputs_.find(input);
248 if (it == inputs_.end()) {
249 return false;
250 }
251
252 inputs_.erase(it);
253 return true;
254}
255
256} // namespace vraudio
257
258#endif // RESONANCE_AUDIO_NODE_NODE_H_
259

source code of qtmultimedia/src/3rdparty/resonance-audio/resonance_audio/node/node.h