xref: /aosp_15_r20/external/oboe/src/flowgraph/FlowGraphNode.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright 2015 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu 
17*05767d91SRobert Wu /*
18*05767d91SRobert Wu  * FlowGraph.h
19*05767d91SRobert Wu  *
20*05767d91SRobert Wu  * Processing node and ports that can be used in a simple data flow graph.
21*05767d91SRobert Wu  * This was designed to work with audio but could be used for other
22*05767d91SRobert Wu  * types of data.
23*05767d91SRobert Wu  */
24*05767d91SRobert Wu 
25*05767d91SRobert Wu #ifndef FLOWGRAPH_FLOW_GRAPH_NODE_H
26*05767d91SRobert Wu #define FLOWGRAPH_FLOW_GRAPH_NODE_H
27*05767d91SRobert Wu 
28*05767d91SRobert Wu #include <cassert>
29*05767d91SRobert Wu #include <cstring>
30*05767d91SRobert Wu #include <math.h>
31*05767d91SRobert Wu #include <memory>
32*05767d91SRobert Wu #include <sys/types.h>
33*05767d91SRobert Wu #include <time.h>
34*05767d91SRobert Wu #include <unistd.h>
35*05767d91SRobert Wu #include <vector>
36*05767d91SRobert Wu 
37*05767d91SRobert Wu // TODO Move these classes into separate files.
38*05767d91SRobert Wu // TODO Review use of raw pointers for connect(). Maybe use smart pointers but need to avoid
39*05767d91SRobert Wu //      run-time deallocation in audio thread.
40*05767d91SRobert Wu 
41*05767d91SRobert Wu // Set flags FLOWGRAPH_ANDROID_INTERNAL and FLOWGRAPH_OUTER_NAMESPACE based on whether compiler
42*05767d91SRobert Wu // flag __ANDROID_NDK__ is defined. __ANDROID_NDK__ should be defined in oboe and not aaudio.
43*05767d91SRobert Wu 
44*05767d91SRobert Wu #ifndef FLOWGRAPH_ANDROID_INTERNAL
45*05767d91SRobert Wu #ifdef __ANDROID_NDK__
46*05767d91SRobert Wu #define FLOWGRAPH_ANDROID_INTERNAL 0
47*05767d91SRobert Wu #else
48*05767d91SRobert Wu #define FLOWGRAPH_ANDROID_INTERNAL 1
49*05767d91SRobert Wu #endif // __ANDROID_NDK__
50*05767d91SRobert Wu #endif // FLOWGRAPH_ANDROID_INTERNAL
51*05767d91SRobert Wu 
52*05767d91SRobert Wu #ifndef FLOWGRAPH_OUTER_NAMESPACE
53*05767d91SRobert Wu #ifdef __ANDROID_NDK__
54*05767d91SRobert Wu #define FLOWGRAPH_OUTER_NAMESPACE oboe
55*05767d91SRobert Wu #else
56*05767d91SRobert Wu #define FLOWGRAPH_OUTER_NAMESPACE aaudio
57*05767d91SRobert Wu #endif // __ANDROID_NDK__
58*05767d91SRobert Wu #endif // FLOWGRAPH_OUTER_NAMESPACE
59*05767d91SRobert Wu 
60*05767d91SRobert Wu namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
61*05767d91SRobert Wu 
62*05767d91SRobert Wu // Default block size that can be overridden when the FlowGraphPortFloat is created.
63*05767d91SRobert Wu // If it is too small then we will have too much overhead from switching between nodes.
64*05767d91SRobert Wu // If it is too high then we will thrash the caches.
65*05767d91SRobert Wu constexpr int kDefaultBufferSize = 8; // arbitrary
66*05767d91SRobert Wu 
67*05767d91SRobert Wu class FlowGraphPort;
68*05767d91SRobert Wu class FlowGraphPortFloatInput;
69*05767d91SRobert Wu 
70*05767d91SRobert Wu /***************************************************************************/
71*05767d91SRobert Wu /**
72*05767d91SRobert Wu  * Base class for all nodes in the flowgraph.
73*05767d91SRobert Wu  */
74*05767d91SRobert Wu class FlowGraphNode {
75*05767d91SRobert Wu public:
76*05767d91SRobert Wu     FlowGraphNode() = default;
77*05767d91SRobert Wu     virtual ~FlowGraphNode() = default;
78*05767d91SRobert Wu 
79*05767d91SRobert Wu     /**
80*05767d91SRobert Wu      * Read from the input ports,
81*05767d91SRobert Wu      * generate multiple frames of data then write the results to the output ports.
82*05767d91SRobert Wu      *
83*05767d91SRobert Wu      * @param numFrames maximum number of frames requested for processing
84*05767d91SRobert Wu      * @return number of frames actually processed
85*05767d91SRobert Wu      */
86*05767d91SRobert Wu     virtual int32_t onProcess(int32_t numFrames) = 0;
87*05767d91SRobert Wu 
88*05767d91SRobert Wu     /**
89*05767d91SRobert Wu      * If the callCount is at or after the previous callCount then call
90*05767d91SRobert Wu      * pullData on all of the upstreamNodes.
91*05767d91SRobert Wu      * Then call onProcess().
92*05767d91SRobert Wu      * This prevents infinite recursion in case of cyclic graphs.
93*05767d91SRobert Wu      * It also prevents nodes upstream from a branch from being executed twice.
94*05767d91SRobert Wu      *
95*05767d91SRobert Wu      * @param callCount
96*05767d91SRobert Wu      * @param numFrames
97*05767d91SRobert Wu      * @return number of frames valid
98*05767d91SRobert Wu      */
99*05767d91SRobert Wu     int32_t pullData(int32_t numFrames, int64_t callCount);
100*05767d91SRobert Wu 
101*05767d91SRobert Wu     /**
102*05767d91SRobert Wu      * Recursively reset all the nodes in the graph, starting from a Sink.
103*05767d91SRobert Wu      *
104*05767d91SRobert Wu      * This must not be called at the same time as pullData!
105*05767d91SRobert Wu      */
106*05767d91SRobert Wu     void pullReset();
107*05767d91SRobert Wu 
108*05767d91SRobert Wu     /**
109*05767d91SRobert Wu      * Reset framePosition counters.
110*05767d91SRobert Wu      */
111*05767d91SRobert Wu     virtual void reset();
112*05767d91SRobert Wu 
addInputPort(FlowGraphPort & port)113*05767d91SRobert Wu     void addInputPort(FlowGraphPort &port) {
114*05767d91SRobert Wu         mInputPorts.emplace_back(port);
115*05767d91SRobert Wu     }
116*05767d91SRobert Wu 
isDataPulledAutomatically()117*05767d91SRobert Wu     bool isDataPulledAutomatically() const {
118*05767d91SRobert Wu         return mDataPulledAutomatically;
119*05767d91SRobert Wu     }
120*05767d91SRobert Wu 
121*05767d91SRobert Wu     /**
122*05767d91SRobert Wu      * Set true if you want the data pulled through the graph automatically.
123*05767d91SRobert Wu      * This is the default.
124*05767d91SRobert Wu      *
125*05767d91SRobert Wu      * Set false if you want to pull the data from the input ports in the onProcess() method.
126*05767d91SRobert Wu      * You might do this, for example, in a sample rate converting node.
127*05767d91SRobert Wu      *
128*05767d91SRobert Wu      * @param automatic
129*05767d91SRobert Wu      */
setDataPulledAutomatically(bool automatic)130*05767d91SRobert Wu     void setDataPulledAutomatically(bool automatic) {
131*05767d91SRobert Wu         mDataPulledAutomatically = automatic;
132*05767d91SRobert Wu     }
133*05767d91SRobert Wu 
getName()134*05767d91SRobert Wu     virtual const char *getName() {
135*05767d91SRobert Wu         return "FlowGraph";
136*05767d91SRobert Wu     }
137*05767d91SRobert Wu 
getLastCallCount()138*05767d91SRobert Wu     int64_t getLastCallCount() {
139*05767d91SRobert Wu         return mLastCallCount;
140*05767d91SRobert Wu     }
141*05767d91SRobert Wu 
142*05767d91SRobert Wu protected:
143*05767d91SRobert Wu 
144*05767d91SRobert Wu     static constexpr int64_t  kInitialCallCount = -1;
145*05767d91SRobert Wu     int64_t  mLastCallCount = kInitialCallCount;
146*05767d91SRobert Wu 
147*05767d91SRobert Wu     std::vector<std::reference_wrapper<FlowGraphPort>> mInputPorts;
148*05767d91SRobert Wu 
149*05767d91SRobert Wu private:
150*05767d91SRobert Wu     bool     mDataPulledAutomatically = true;
151*05767d91SRobert Wu     bool     mBlockRecursion = false;
152*05767d91SRobert Wu     int32_t  mLastFrameCount = 0;
153*05767d91SRobert Wu 
154*05767d91SRobert Wu };
155*05767d91SRobert Wu 
156*05767d91SRobert Wu /***************************************************************************/
157*05767d91SRobert Wu /**
158*05767d91SRobert Wu   * This is a connector that allows data to flow between modules.
159*05767d91SRobert Wu   *
160*05767d91SRobert Wu   * The ports are the primary means of interacting with a module.
161*05767d91SRobert Wu   * So they are generally declared as public.
162*05767d91SRobert Wu   *
163*05767d91SRobert Wu   */
164*05767d91SRobert Wu class FlowGraphPort {
165*05767d91SRobert Wu public:
FlowGraphPort(FlowGraphNode & parent,int32_t samplesPerFrame)166*05767d91SRobert Wu     FlowGraphPort(FlowGraphNode &parent, int32_t samplesPerFrame)
167*05767d91SRobert Wu             : mContainingNode(parent)
168*05767d91SRobert Wu             , mSamplesPerFrame(samplesPerFrame) {
169*05767d91SRobert Wu     }
170*05767d91SRobert Wu 
171*05767d91SRobert Wu     virtual ~FlowGraphPort() = default;
172*05767d91SRobert Wu 
173*05767d91SRobert Wu     // Ports are often declared public. So let's make them non-copyable.
174*05767d91SRobert Wu     FlowGraphPort(const FlowGraphPort&) = delete;
175*05767d91SRobert Wu     FlowGraphPort& operator=(const FlowGraphPort&) = delete;
176*05767d91SRobert Wu 
getSamplesPerFrame()177*05767d91SRobert Wu     int32_t getSamplesPerFrame() const {
178*05767d91SRobert Wu         return mSamplesPerFrame;
179*05767d91SRobert Wu     }
180*05767d91SRobert Wu 
181*05767d91SRobert Wu     virtual int32_t pullData(int64_t framePosition, int32_t numFrames) = 0;
182*05767d91SRobert Wu 
pullReset()183*05767d91SRobert Wu     virtual void pullReset() {}
184*05767d91SRobert Wu 
185*05767d91SRobert Wu protected:
186*05767d91SRobert Wu     FlowGraphNode &mContainingNode;
187*05767d91SRobert Wu 
188*05767d91SRobert Wu private:
189*05767d91SRobert Wu     const int32_t    mSamplesPerFrame = 1;
190*05767d91SRobert Wu };
191*05767d91SRobert Wu 
192*05767d91SRobert Wu /***************************************************************************/
193*05767d91SRobert Wu /**
194*05767d91SRobert Wu  * This port contains a 32-bit float buffer that can contain several frames of data.
195*05767d91SRobert Wu  * Processing the data in a block improves performance.
196*05767d91SRobert Wu  *
197*05767d91SRobert Wu  * The size is framesPerBuffer * samplesPerFrame).
198*05767d91SRobert Wu  */
199*05767d91SRobert Wu class FlowGraphPortFloat  : public FlowGraphPort {
200*05767d91SRobert Wu public:
201*05767d91SRobert Wu     FlowGraphPortFloat(FlowGraphNode &parent,
202*05767d91SRobert Wu                    int32_t samplesPerFrame,
203*05767d91SRobert Wu                    int32_t framesPerBuffer = kDefaultBufferSize
204*05767d91SRobert Wu                 );
205*05767d91SRobert Wu 
206*05767d91SRobert Wu     virtual ~FlowGraphPortFloat() = default;
207*05767d91SRobert Wu 
getFramesPerBuffer()208*05767d91SRobert Wu     int32_t getFramesPerBuffer() const {
209*05767d91SRobert Wu         return mFramesPerBuffer;
210*05767d91SRobert Wu     }
211*05767d91SRobert Wu 
212*05767d91SRobert Wu protected:
213*05767d91SRobert Wu 
214*05767d91SRobert Wu     /**
215*05767d91SRobert Wu      * @return buffer internal to the port or from a connected port
216*05767d91SRobert Wu      */
getBuffer()217*05767d91SRobert Wu     virtual float *getBuffer() {
218*05767d91SRobert Wu         return mBuffer.get();
219*05767d91SRobert Wu     }
220*05767d91SRobert Wu 
221*05767d91SRobert Wu private:
222*05767d91SRobert Wu     const int32_t    mFramesPerBuffer = 1;
223*05767d91SRobert Wu     std::unique_ptr<float[]> mBuffer; // allocated in constructor
224*05767d91SRobert Wu };
225*05767d91SRobert Wu 
226*05767d91SRobert Wu /***************************************************************************/
227*05767d91SRobert Wu /**
228*05767d91SRobert Wu   * The results of a node's processing are stored in the buffers of the output ports.
229*05767d91SRobert Wu   */
230*05767d91SRobert Wu class FlowGraphPortFloatOutput : public FlowGraphPortFloat {
231*05767d91SRobert Wu public:
FlowGraphPortFloatOutput(FlowGraphNode & parent,int32_t samplesPerFrame)232*05767d91SRobert Wu     FlowGraphPortFloatOutput(FlowGraphNode &parent, int32_t samplesPerFrame)
233*05767d91SRobert Wu             : FlowGraphPortFloat(parent, samplesPerFrame) {
234*05767d91SRobert Wu     }
235*05767d91SRobert Wu 
236*05767d91SRobert Wu     virtual ~FlowGraphPortFloatOutput() = default;
237*05767d91SRobert Wu 
238*05767d91SRobert Wu     using FlowGraphPortFloat::getBuffer;
239*05767d91SRobert Wu 
240*05767d91SRobert Wu     /**
241*05767d91SRobert Wu      * Connect to the input of another module.
242*05767d91SRobert Wu      * An input port can only have one connection.
243*05767d91SRobert Wu      * An output port can have multiple connections.
244*05767d91SRobert Wu      * If you connect a second output port to an input port
245*05767d91SRobert Wu      * then it overwrites the previous connection.
246*05767d91SRobert Wu      *
247*05767d91SRobert Wu      * This not thread safe. Do not modify the graph topology from another thread while running.
248*05767d91SRobert Wu      * Also do not delete a module while it is connected to another port if the graph is running.
249*05767d91SRobert Wu      */
250*05767d91SRobert Wu     void connect(FlowGraphPortFloatInput *port);
251*05767d91SRobert Wu 
252*05767d91SRobert Wu     /**
253*05767d91SRobert Wu      * Disconnect from the input of another module.
254*05767d91SRobert Wu      * This not thread safe.
255*05767d91SRobert Wu      */
256*05767d91SRobert Wu     void disconnect(FlowGraphPortFloatInput *port);
257*05767d91SRobert Wu 
258*05767d91SRobert Wu     /**
259*05767d91SRobert Wu      * Call the parent module's onProcess() method.
260*05767d91SRobert Wu      * That may pull data from its inputs and recursively
261*05767d91SRobert Wu      * process the entire graph.
262*05767d91SRobert Wu      * @return number of frames actually pulled
263*05767d91SRobert Wu      */
264*05767d91SRobert Wu     int32_t pullData(int64_t framePosition, int32_t numFrames) override;
265*05767d91SRobert Wu 
266*05767d91SRobert Wu 
267*05767d91SRobert Wu     void pullReset() override;
268*05767d91SRobert Wu 
269*05767d91SRobert Wu };
270*05767d91SRobert Wu 
271*05767d91SRobert Wu /***************************************************************************/
272*05767d91SRobert Wu 
273*05767d91SRobert Wu /**
274*05767d91SRobert Wu  * An input port for streaming audio data.
275*05767d91SRobert Wu  * You can set a value that will be used for processing.
276*05767d91SRobert Wu  * If you connect an output port to this port then its value will be used instead.
277*05767d91SRobert Wu  */
278*05767d91SRobert Wu class FlowGraphPortFloatInput : public FlowGraphPortFloat {
279*05767d91SRobert Wu public:
FlowGraphPortFloatInput(FlowGraphNode & parent,int32_t samplesPerFrame)280*05767d91SRobert Wu     FlowGraphPortFloatInput(FlowGraphNode &parent, int32_t samplesPerFrame)
281*05767d91SRobert Wu             : FlowGraphPortFloat(parent, samplesPerFrame) {
282*05767d91SRobert Wu         // Add to parent so it can pull data from each input.
283*05767d91SRobert Wu         parent.addInputPort(*this);
284*05767d91SRobert Wu     }
285*05767d91SRobert Wu 
286*05767d91SRobert Wu     virtual ~FlowGraphPortFloatInput() = default;
287*05767d91SRobert Wu 
288*05767d91SRobert Wu     /**
289*05767d91SRobert Wu      * If connected to an output port then this will return
290*05767d91SRobert Wu      * that output ports buffers.
291*05767d91SRobert Wu      * If not connected then it returns the input ports own buffer
292*05767d91SRobert Wu      * which can be loaded using setValue().
293*05767d91SRobert Wu      */
294*05767d91SRobert Wu     float *getBuffer() override;
295*05767d91SRobert Wu 
296*05767d91SRobert Wu     /**
297*05767d91SRobert Wu      * Write every value of the float buffer.
298*05767d91SRobert Wu      * This value will be ignored if an output port is connected
299*05767d91SRobert Wu      * to this port.
300*05767d91SRobert Wu      */
setValue(float value)301*05767d91SRobert Wu     void setValue(float value) {
302*05767d91SRobert Wu         int numFloats = kDefaultBufferSize * getSamplesPerFrame();
303*05767d91SRobert Wu         float *buffer = getBuffer();
304*05767d91SRobert Wu         for (int i = 0; i < numFloats; i++) {
305*05767d91SRobert Wu             *buffer++ = value;
306*05767d91SRobert Wu         }
307*05767d91SRobert Wu     }
308*05767d91SRobert Wu 
309*05767d91SRobert Wu     /**
310*05767d91SRobert Wu      * Connect to the output of another module.
311*05767d91SRobert Wu      * An input port can only have one connection.
312*05767d91SRobert Wu      * An output port can have multiple connections.
313*05767d91SRobert Wu      * This not thread safe.
314*05767d91SRobert Wu      */
connect(FlowGraphPortFloatOutput * port)315*05767d91SRobert Wu     void connect(FlowGraphPortFloatOutput *port) {
316*05767d91SRobert Wu         assert(getSamplesPerFrame() == port->getSamplesPerFrame());
317*05767d91SRobert Wu         mConnected = port;
318*05767d91SRobert Wu     }
319*05767d91SRobert Wu 
disconnect(FlowGraphPortFloatOutput * port)320*05767d91SRobert Wu     void disconnect(FlowGraphPortFloatOutput *port) {
321*05767d91SRobert Wu         assert(mConnected == port);
322*05767d91SRobert Wu         (void) port;
323*05767d91SRobert Wu         mConnected = nullptr;
324*05767d91SRobert Wu     }
325*05767d91SRobert Wu 
disconnect()326*05767d91SRobert Wu     void disconnect() {
327*05767d91SRobert Wu         mConnected = nullptr;
328*05767d91SRobert Wu     }
329*05767d91SRobert Wu 
330*05767d91SRobert Wu     /**
331*05767d91SRobert Wu      * Pull data from any output port that is connected.
332*05767d91SRobert Wu      */
333*05767d91SRobert Wu     int32_t pullData(int64_t framePosition, int32_t numFrames) override;
334*05767d91SRobert Wu 
335*05767d91SRobert Wu     void pullReset() override;
336*05767d91SRobert Wu 
337*05767d91SRobert Wu private:
338*05767d91SRobert Wu     FlowGraphPortFloatOutput *mConnected = nullptr;
339*05767d91SRobert Wu };
340*05767d91SRobert Wu 
341*05767d91SRobert Wu /***************************************************************************/
342*05767d91SRobert Wu 
343*05767d91SRobert Wu /**
344*05767d91SRobert Wu  * Base class for an edge node in a graph that has no upstream nodes.
345*05767d91SRobert Wu  * It outputs data but does not consume data.
346*05767d91SRobert Wu  * By default, it will read its data from an external buffer.
347*05767d91SRobert Wu  */
348*05767d91SRobert Wu class FlowGraphSource : public FlowGraphNode {
349*05767d91SRobert Wu public:
FlowGraphSource(int32_t channelCount)350*05767d91SRobert Wu     explicit FlowGraphSource(int32_t channelCount)
351*05767d91SRobert Wu             : output(*this, channelCount) {
352*05767d91SRobert Wu     }
353*05767d91SRobert Wu 
354*05767d91SRobert Wu     virtual ~FlowGraphSource() = default;
355*05767d91SRobert Wu 
356*05767d91SRobert Wu     FlowGraphPortFloatOutput output;
357*05767d91SRobert Wu };
358*05767d91SRobert Wu 
359*05767d91SRobert Wu /***************************************************************************/
360*05767d91SRobert Wu 
361*05767d91SRobert Wu /**
362*05767d91SRobert Wu  * Base class for an edge node in a graph that has no upstream nodes.
363*05767d91SRobert Wu  * It outputs data but does not consume data.
364*05767d91SRobert Wu  * By default, it will read its data from an external buffer.
365*05767d91SRobert Wu  */
366*05767d91SRobert Wu class FlowGraphSourceBuffered : public FlowGraphSource {
367*05767d91SRobert Wu public:
FlowGraphSourceBuffered(int32_t channelCount)368*05767d91SRobert Wu     explicit FlowGraphSourceBuffered(int32_t channelCount)
369*05767d91SRobert Wu             : FlowGraphSource(channelCount) {}
370*05767d91SRobert Wu 
371*05767d91SRobert Wu     virtual ~FlowGraphSourceBuffered() = default;
372*05767d91SRobert Wu 
373*05767d91SRobert Wu     /**
374*05767d91SRobert Wu      * Specify buffer that the node will read from.
375*05767d91SRobert Wu      *
376*05767d91SRobert Wu      * @param data TODO Consider using std::shared_ptr.
377*05767d91SRobert Wu      * @param numFrames
378*05767d91SRobert Wu      */
setData(const void * data,int32_t numFrames)379*05767d91SRobert Wu     void setData(const void *data, int32_t numFrames) {
380*05767d91SRobert Wu         mData = data;
381*05767d91SRobert Wu         mSizeInFrames = numFrames;
382*05767d91SRobert Wu         mFrameIndex = 0;
383*05767d91SRobert Wu     }
384*05767d91SRobert Wu 
385*05767d91SRobert Wu protected:
386*05767d91SRobert Wu     const void *mData = nullptr;
387*05767d91SRobert Wu     int32_t     mSizeInFrames = 0; // number of frames in mData
388*05767d91SRobert Wu     int32_t     mFrameIndex = 0; // index of next frame to be processed
389*05767d91SRobert Wu };
390*05767d91SRobert Wu 
391*05767d91SRobert Wu /***************************************************************************/
392*05767d91SRobert Wu /**
393*05767d91SRobert Wu  * Base class for an edge node in a graph that has no downstream nodes.
394*05767d91SRobert Wu  * It consumes data but does not output data.
395*05767d91SRobert Wu  * This graph will be executed when data is read() from this node
396*05767d91SRobert Wu  * by pulling data from upstream nodes.
397*05767d91SRobert Wu  */
398*05767d91SRobert Wu class FlowGraphSink : public FlowGraphNode {
399*05767d91SRobert Wu public:
FlowGraphSink(int32_t channelCount)400*05767d91SRobert Wu     explicit FlowGraphSink(int32_t channelCount)
401*05767d91SRobert Wu             : input(*this, channelCount) {
402*05767d91SRobert Wu     }
403*05767d91SRobert Wu 
404*05767d91SRobert Wu     virtual ~FlowGraphSink() = default;
405*05767d91SRobert Wu 
406*05767d91SRobert Wu     FlowGraphPortFloatInput input;
407*05767d91SRobert Wu 
408*05767d91SRobert Wu     /**
409*05767d91SRobert Wu      * Do nothing. The work happens in the read() method.
410*05767d91SRobert Wu      *
411*05767d91SRobert Wu      * @param numFrames
412*05767d91SRobert Wu      * @return number of frames actually processed
413*05767d91SRobert Wu      */
onProcess(int32_t numFrames)414*05767d91SRobert Wu     int32_t onProcess(int32_t numFrames) override {
415*05767d91SRobert Wu         return numFrames;
416*05767d91SRobert Wu     }
417*05767d91SRobert Wu 
418*05767d91SRobert Wu     virtual int32_t read(void *data, int32_t numFrames) = 0;
419*05767d91SRobert Wu 
420*05767d91SRobert Wu protected:
421*05767d91SRobert Wu     /**
422*05767d91SRobert Wu      * Pull data through the graph using this nodes last callCount.
423*05767d91SRobert Wu      * @param numFrames
424*05767d91SRobert Wu      * @return
425*05767d91SRobert Wu      */
426*05767d91SRobert Wu     int32_t pullData(int32_t numFrames);
427*05767d91SRobert Wu };
428*05767d91SRobert Wu 
429*05767d91SRobert Wu /***************************************************************************/
430*05767d91SRobert Wu /**
431*05767d91SRobert Wu  * Base class for a node that has an input and an output with the same number of channels.
432*05767d91SRobert Wu  * This may include traditional filters, eg. FIR, but also include
433*05767d91SRobert Wu  * any processing node that converts input to output.
434*05767d91SRobert Wu  */
435*05767d91SRobert Wu class FlowGraphFilter : public FlowGraphNode {
436*05767d91SRobert Wu public:
FlowGraphFilter(int32_t channelCount)437*05767d91SRobert Wu     explicit FlowGraphFilter(int32_t channelCount)
438*05767d91SRobert Wu             : input(*this, channelCount)
439*05767d91SRobert Wu             , output(*this, channelCount) {
440*05767d91SRobert Wu     }
441*05767d91SRobert Wu 
442*05767d91SRobert Wu     virtual ~FlowGraphFilter() = default;
443*05767d91SRobert Wu 
444*05767d91SRobert Wu     FlowGraphPortFloatInput input;
445*05767d91SRobert Wu     FlowGraphPortFloatOutput output;
446*05767d91SRobert Wu };
447*05767d91SRobert Wu 
448*05767d91SRobert Wu } /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
449*05767d91SRobert Wu 
450*05767d91SRobert Wu #endif /* FLOWGRAPH_FLOW_GRAPH_NODE_H */
451