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

Revision 748, 17.6 kB (checked in by ppalmers, 15 years ago)

try to reorganize things such that less information is duplicated

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