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