root/trunk/libffado/src/libstreaming/generic/StreamProcessor.h

Revision 742, 17.0 kB (checked in by ppalmers, 13 years ago)

- Remove some obsolete support files and dirs

- Clean up the license statements in the source files. Everything is

GPL version 3 now.

- Add license and copyright notices to scons scripts

- Clean up some other text files

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #ifndef __FFADO_STREAMPROCESSOR__
25 #define __FFADO_STREAMPROCESSOR__
26
27 #include "IsoStream.h"
28 #include "PortManager.h"
29
30 #include "libutil/StreamStatistics.h"
31 #include "libutil/TimestampedBuffer.h"
32 #include "libutil/OptionContainer.h"
33
34 #include "debugmodule/debugmodule.h"
35
36 #include <pthread.h>
37
38 namespace Streaming {
39
40     class StreamProcessorManager;
41 /*!
42 \brief Class providing a generic interface for Stream Processors
43
44  A stream processor multiplexes or demultiplexes an ISO stream into a
45  collection of ports. This class should be subclassed, and the relevant
46  functions should be overloaded.
47
48 */
49 class StreamProcessor : public IsoStream,
50                         public PortManager,
51                         public Util::TimestampedBufferClient,
52                         public Util::OptionContainer
53 {
54
55     friend class StreamProcessorManager; // FIXME: get rid of this
56
57 public:
58     ///> the streamprocessor type
59     enum eProcessorType {
60         ePT_Receive,
61         ePT_Transmit
62     };
63     ///> returns the type of the streamprocessor
64     virtual enum eProcessorType getType() { return m_processor_type; };
65 private:
66     // this can only be set by the constructor
67     enum eProcessorType m_processor_type;
68     // pretty printing
69     const char *ePTToString(enum eProcessorType);
70 protected:
71     ///> the state the streamprocessor is in
72     enum eProcessorState {
73         ePS_Invalid,
74         ePS_Created,
75         // ePS_WaitingToStop, FIXME: this will be needed for the MOTU's
76         ePS_Stopped,
77         ePS_WaitingForStream,
78         ePS_DryRunning,
79         ePS_WaitingForStreamEnable,
80         ePS_Running,
81         ePS_WaitingForStreamDisable,
82     };
83
84     ///> set the SP state to a specific value
85     void setState(enum eProcessorState);
86     ///> get the SP state
87     enum eProcessorState getState() {return m_state;};
88 private:
89     enum eProcessorState m_state;
90     // state switching
91     enum eProcessorState m_next_state;
92     unsigned int m_cycle_to_switch_state;
93     bool updateState();
94     // pretty printing
95     const char *ePSToString(enum eProcessorState);
96
97     bool doStop();
98     bool doWaitForRunningStream();
99     bool doDryRunning();
100     bool doWaitForStreamEnable();
101     bool doRunning();
102     bool doWaitForStreamDisable();
103
104     bool scheduleStateTransition(enum eProcessorState state, uint64_t time_instant);
105     bool waitForState(enum eProcessorState state, unsigned int timeout);
106
107 public: //--- state stuff
108     bool isRunning()
109             {return m_state == ePS_Running;};
110     bool isDryRunning()
111             {return m_state == ePS_DryRunning;};
112     bool isStopped()
113             {return m_state == ePS_Stopped;};
114
115     // these schedule and wait for the state transition
116     bool startDryRunning(int64_t time_to_start_at);
117     bool startRunning(int64_t time_to_start_at);
118     bool stopDryRunning(int64_t time_to_stop_at);
119     bool stopRunning(int64_t time_to_stop_at);
120
121     // these only schedule the transition
122     bool scheduleStartDryRunning(int64_t time_to_start_at);
123     bool scheduleStartRunning(int64_t time_to_start_at);
124     bool scheduleStopDryRunning(int64_t time_to_stop_at);
125     bool scheduleStopRunning(int64_t time_to_stop_at);
126
127     // the main difference between init and prepare is that when prepare is called,
128     // the SP is registered to a manager (FIXME: can't it be called by the manager?)
129     bool init();
130     bool prepare();
131
132 public: // constructor/destructor
133     StreamProcessor(enum eProcessorType type, int port);
134     virtual ~StreamProcessor();
135
136 public: // the public receive/transmit functions
137     // the transmit interface accepts frames and provides packets
138     // implement these for a transmit SP
139     // leave default for a receive SP
140
141     // the receive interface accepts packets and provides frames
142     // these are implemented by the parent SP
143     enum raw1394_iso_disposition
144         putPacket(unsigned char *data, unsigned int length,
145                   unsigned char channel, unsigned char tag, unsigned char sy,
146                   unsigned int cycle, unsigned int dropped);
147
148     enum raw1394_iso_disposition
149     getPacket(unsigned char *data, unsigned int *length,
150                 unsigned char *tag, unsigned char *sy,
151                 int cycle, unsigned int dropped, unsigned int max_length);
152
153     bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client
154     bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the client contents to the buffer
155
156     /**
157      * @brief drop nframes from the internal buffer as if they were transferred to the client side
158      *
159      * Gets nframes of frames from the buffer as done by getFrames(), but does not transfer them
160      * to the client side. Instead they are discarded.
161      *
162      * @param nframes number of frames
163      * @return true if the operation was successful
164      */
165     bool dropFrames(unsigned int nframes, int64_t ts);
166
167     /**
168      * @brief put silence frames into the internal buffer
169      *
170      * Puts nframes of frames into the buffer as done by putFrames(), but does not transfer them
171      * from the client side. Instead, silent frames are used.
172      *
173      * @param nframes number of frames
174      * @return true if the operation was successful
175      */
176     bool putSilenceFrames(unsigned int nbframes, int64_t ts);
177    
178     /**
179      * @brief Shifts the stream with the specified number of frames
180      *
181      * Used to align several streams to each other. It comes down to
182      * making sure the head timestamp corresponds to the timestamp of
183      * one master stream
184      *
185      * @param nframes the number of frames to shift
186      * @return true if successful
187      */
188     bool shiftStream(int nframes);
189 protected: // the helper receive/transmit functions
190     enum eChildReturnValue {
191         eCRV_OK,
192         eCRV_Invalid,
193         eCRV_Packet,
194         eCRV_EmptyPacket,
195         eCRV_XRun,
196         eCRV_Again,
197     };
198     // to be implemented by the children
199     // the following methods are to be implemented by receive SP subclasses
200     virtual enum eChildReturnValue processPacketHeader(unsigned char *data, unsigned int length,
201                                      unsigned char channel, unsigned char tag,
202                                      unsigned char sy, unsigned int cycle,
203                                      unsigned int dropped)
204         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
205     virtual enum eChildReturnValue processPacketData(unsigned char *data, unsigned int length,
206                                    unsigned char channel, unsigned char tag,
207                                    unsigned char sy, unsigned int cycle,
208                                    unsigned int dropped)
209         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
210     virtual bool processReadBlock(char *data, unsigned int nevents, unsigned int offset)
211         {debugWarning("call not allowed\n"); return false;};
212
213     // the following methods are to be implemented by transmit SP subclasses
214     virtual enum eChildReturnValue generatePacketHeader(unsigned char *data, unsigned int *length,
215                                       unsigned char *tag, unsigned char *sy,
216                                       int cycle, unsigned int dropped,
217                                       unsigned int max_length)
218         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
219     virtual enum eChildReturnValue generatePacketData(unsigned char *data, unsigned int *length,
220                                     unsigned char *tag, unsigned char *sy,
221                                     int cycle, unsigned int dropped,
222                                     unsigned int max_length)
223         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
224     virtual enum eChildReturnValue generateSilentPacketHeader(unsigned char *data, unsigned int *length,
225                                             unsigned char *tag, unsigned char *sy,
226                                             int cycle, unsigned int dropped,
227                                             unsigned int max_length)
228         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
229     virtual enum eChildReturnValue generateSilentPacketData(unsigned char *data, unsigned int *length,
230                                           unsigned char *tag, unsigned char *sy,
231                                           int cycle, unsigned int dropped,
232                                           unsigned int max_length)
233         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
234     virtual bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset)
235         {debugWarning("call not allowed\n"); return false;};
236     virtual bool transmitSilenceBlock(char *data, unsigned int nevents, unsigned int offset)
237         {debugWarning("call not allowed\n"); return false;};
238 protected: // some generic helpers
239     int provideSilenceToPort(AudioPort *p, unsigned int offset, unsigned int nevents);
240     bool provideSilenceBlock(unsigned int nevents, unsigned int offset);
241
242 private:
243     bool getFramesDry(unsigned int nbframes, int64_t ts);
244     bool getFramesWet(unsigned int nbframes, int64_t ts);
245     bool putFramesDry(unsigned int nbframes, int64_t ts);
246     bool putFramesWet(unsigned int nbframes, int64_t ts);
247
248     bool transferSilence(unsigned int size);
249
250     // move to private?
251     bool xrunOccurred() { return m_in_xrun; };
252
253 protected: // FIXME: move to private
254     uint64_t m_dropped; /// FIXME:debug
255     uint64_t m_last_dropped; /// FIXME:debug
256     int m_last_good_cycle; /// FIXME:debug
257     uint64_t m_last_timestamp; /// last timestamp (in ticks)
258     uint64_t m_last_timestamp2; /// last timestamp (in ticks)
259     uint64_t m_last_timestamp_at_period_ticks;
260
261 //--- data buffering and accounting
262 public:
263     void getBufferHeadTimestamp ( ffado_timestamp_t *ts, signed int *fc )
264         {m_data_buffer->getBufferHeadTimestamp(ts, fc);};
265     void getBufferTailTimestamp ( ffado_timestamp_t *ts, signed int *fc )
266         {m_data_buffer->getBufferTailTimestamp(ts, fc);};
267
268     void setBufferTailTimestamp ( ffado_timestamp_t new_timestamp )
269         {m_data_buffer->setBufferTailTimestamp(new_timestamp);};
270     void setBufferHeadTimestamp ( ffado_timestamp_t new_timestamp )
271         {m_data_buffer->setBufferHeadTimestamp(new_timestamp);};
272 protected:
273     Util::TimestampedBuffer *m_data_buffer;
274     // the scratch buffer is temporary buffer space that can be
275     // used by any function. It's pre-allocated when the SP is created.
276     // the purpose is to avoid allocation of memory (or heap/stack) in
277     // an RT context
278     byte_t*         m_scratch_buffer;
279     size_t          m_scratch_buffer_size_bytes;
280 protected:
281     StreamProcessorManager *m_manager;
282
283     // frame counter & sync stuff
284     public:
285         /**
286          * @brief Can this StreamProcessor handle a transfer of nframes frames?
287          *
288          * this function indicates if the streamprocessor can handle a transfer of
289          * nframes frames. It is used to detect underruns-to-be.
290          *
291          * @param nframes number of frames
292          * @return true if the StreamProcessor can handle this amount of frames
293          *         false if it can't
294          */
295         bool canClientTransferFrames(unsigned int nframes);
296
297         /**
298          * \brief return the time until the next period boundary should be signaled (in microseconds)
299          *
300          * Return the time until the next period boundary signal. If this StreamProcessor
301          * is the current synchronization source, this function is called to
302          * determine when a buffer transfer can be made. When this value is
303          * smaller than 0, a period boundary is assumed to be crossed, hence a
304          * transfer can be made.
305          *
306          * \return the time in usecs
307          */
308         int64_t getTimeUntilNextPeriodSignalUsecs();
309         /**
310          * \brief return the time of the next period boundary (in microseconds)
311          *
312          * Returns the time of the next period boundary, in microseconds. The
313          * goal of this function is to determine the exact point of the period
314          * boundary. This is assumed to be the point at which the buffer transfer should
315          * take place, meaning that it can be used as a reference timestamp for transmitting
316          * StreamProcessors
317          *
318          * \return the time in usecs
319          */
320         uint64_t getTimeAtPeriodUsecs();
321
322         /**
323          * \brief return the time of the next period boundary (in internal units)
324          *
325          * The same as getTimeAtPeriodUsecs() but in internal units.
326          *
327          * @return the time in internal units
328          */
329         uint64_t getTimeAtPeriod();
330
331         uint64_t getTimeNow(); // FIXME: should disappear
332
333
334         /**
335          * Returns the sync delay. This is the time a syncsource
336          * delays a period signal, e.g. to cope with buffering.
337          * @return the sync delay
338          */
339         int getSyncDelay() {return m_sync_delay;};
340         /**
341          * sets the sync delay
342          * @param d sync delay
343          */
344         void setSyncDelay(int d);
345
346         /**
347          * @brief get the maximal frame latency
348          *
349          * The maximum frame latency is the maximum time that will elapse
350          * between the frame being received by the 1394 stack, and the moment this
351          * frame is presented to the StreamProcessor.
352          *
353          * For transmit SP's this is the maximum time that a frame is requested by
354          * the handler ahead of the time the frame is intended to be transmitted.
355          *
356          * This is useful to figure out how longer than the actual reception time
357          * we have to wait before trying to read the frame from the SP.
358          *
359          * @return maximal frame latency
360          */
361         int getMaxFrameLatency();
362
363         float getTicksPerFrame();
364
365         int getLastCycle() {return m_last_cycle;};
366
367         int getBufferFill();
368
369         // Child implementation interface
370         /**
371         * @brief prepare the child SP
372         * @return true if successful, false otherwise
373         * @pre the m_manager pointer points to a valid manager
374         * @post getEventsPerFrame() returns the correct value
375         * @post getEventSize() returns the correct value
376         * @post getUpdatePeriod() returns the correct value
377         * @post processPacketHeader(...) can be called
378         * @post processPacketData(...) can be called
379         */
380         virtual bool prepareChild() = 0;
381         /**
382          * @brief get the number of events contained in one frame
383          * @return the number of events contained in one frame
384          */
385         virtual unsigned int getEventsPerFrame() = 0;
386
387         /**
388          * @brief get the size of one frame in bytes
389          * @return the size of one frame in bytes
390          */
391         virtual unsigned int getEventSize() = 0;
392
393         /**
394          * @brief get the nominal number of frames in a packet
395          *
396          * This is the amount of frames that is nominally present
397          * in one packet. It is recommended that in the receive handler
398          * you write this amount of frames when a valid packet has
399          * been received. (although this is not mandatory)
400          *
401          * @return the nominal number of frames in a packet
402          */
403         virtual unsigned int getNominalFramesPerPacket() = 0;
404
405         /**
406          * @brief get the nominal number of packets needed for a certain amount of frames
407          * @return the nominal number of packet necessary
408          */
409         virtual unsigned int getNominalPacketsNeeded(unsigned int nframes);
410
411         /**
412          * @brief returns the actual frame rate as calculated by the SP's DLL
413          * @return the actual frame rate as detected by the DLL
414          */
415         float getActualRate()
416             {return m_data_buffer->getRate();};
417
418     protected:
419         float m_ticks_per_frame;
420         int m_last_cycle;
421         int m_sync_delay;
422     private:
423         bool m_in_xrun;
424
425 protected: // SPM related
426     void setManager(StreamProcessorManager *manager) {m_manager=manager;};
427     void clearManager() {m_manager=NULL;};
428
429 public:
430     // debug stuff
431     virtual void dumpInfo();
432     virtual void setVerboseLevel(int l);
433     const char *getStateString()
434         {return ePSToString(getState());};
435     const char *getTypeString()
436         {return ePTToString(getType());};
437     StreamStatistics m_PacketStat;
438     StreamStatistics m_PeriodStat;
439     StreamStatistics m_WakeupStat;
440     DECLARE_DEBUG_MODULE;
441 };
442
443 }
444
445 #endif /* __FFADO_STREAMPROCESSOR__ */
446
447
Note: See TracBrowser for help on using the browser.