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

Revision 860, 19.0 kB (checked in by ppalmers, 15 years ago)

clean up synchronization in streamprocessor

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
29 #include "PortManager.h"
30
31 #include "libutil/StreamStatistics.h"
32 #include "libutil/TimestampedBuffer.h"
33 #include "libutil/OptionContainer.h"
34
35 #include "debugmodule/debugmodule.h"
36
37 #include <pthread.h>
38
39 class Ieee1394Service;
40 class IsoHandlerManager;
41
42 namespace Streaming {
43
44     class StreamProcessorManager;
45 /*!
46 \brief Class providing a generic interface for Stream Processors
47
48  A stream processor multiplexes or demultiplexes an ISO stream into a
49  collection of ports. This class should be subclassed, and the relevant
50  functions should be overloaded.
51
52 */
53 class StreamProcessor : public PortManager,
54                         public Util::TimestampedBufferClient,
55                         public Util::OptionContainer
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     bool isWaitingForStream()
115             {return m_state == ePS_WaitingForStream;};
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     Ieee1394Service&            m_1394service;
140     IsoHandlerManager&          m_IsoHandlerManager;
141     StreamProcessorManager&     m_StreamProcessorManager;
142     unsigned int                m_local_node_id;
143
144 public: // the public receive/transmit functions
145     // the transmit interface accepts frames and provides packets
146     // implement these for a transmit SP
147     // leave default for a receive SP
148
149     // the receive interface accepts packets and provides frames
150     // these are implemented by the parent SP
151     enum raw1394_iso_disposition
152         putPacket(unsigned char *data, unsigned int length,
153                   unsigned char channel, unsigned char tag, unsigned char sy,
154                   unsigned int cycle, unsigned int dropped);
155
156     enum raw1394_iso_disposition
157     getPacket(unsigned char *data, unsigned int *length,
158                 unsigned char *tag, unsigned char *sy,
159                 int cycle, unsigned int dropped, unsigned int max_length);
160
161     bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client
162     bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the client contents to the buffer
163
164     //FIXME: document wait functions
165     bool waitForProducePacket();
166     bool waitForProducePeriod();
167     bool waitForProduce(unsigned int nframes);
168
169     bool waitForConsumePacket();
170     bool waitForConsumePeriod();
171     bool waitForConsume(unsigned int nframes);
172
173     bool canProducePacket();
174     bool canProducePeriod();
175     bool canProduce(unsigned int nframes);
176
177     bool canConsumePacket();
178     bool canConsumePeriod();
179     bool canConsume(unsigned int nframes);
180
181 public:
182     /**
183      * @brief drop nframes from the internal buffer as if they were transferred to the client side
184      *
185      * Gets nframes of frames from the buffer as done by getFrames(), but does not transfer them
186      * to the client side. Instead they are discarded.
187      *
188      * @param nframes number of frames
189      * @return true if the operation was successful
190      */
191     bool dropFrames(unsigned int nframes, int64_t ts);
192
193     /**
194      * @brief put silence frames into the internal buffer
195      *
196      * Puts nframes of frames into the buffer as done by putFrames(), but does not transfer them
197      * from the client side. Instead, silent frames are used.
198      *
199      * @param nframes number of frames
200      * @return true if the operation was successful
201      */
202     bool putSilenceFrames(unsigned int nbframes, int64_t ts);
203
204     /**
205      * @brief Shifts the stream with the specified number of frames
206      *
207      * Used to align several streams to each other. It comes down to
208      * making sure the head timestamp corresponds to the timestamp of
209      * one master stream
210      *
211      * @param nframes the number of frames to shift
212      * @return true if successful
213      */
214     bool shiftStream(int nframes);
215
216     /**
217      * @brief tries to fill/sink the stream as far as possible
218      */
219     void flush();
220
221 protected: // the helper receive/transmit functions
222     enum eChildReturnValue {
223         eCRV_OK,
224         eCRV_Invalid,
225         eCRV_Packet,
226         eCRV_EmptyPacket,
227         eCRV_XRun,
228         eCRV_Again,
229         eCRV_Defer,
230     };
231     // to be implemented by the children
232     // the following methods are to be implemented by receive SP subclasses
233     virtual enum eChildReturnValue processPacketHeader(unsigned char *data, unsigned int length,
234                                      unsigned char channel, unsigned char tag,
235                                      unsigned char sy, unsigned int cycle,
236                                      unsigned int dropped)
237         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
238     virtual enum eChildReturnValue processPacketData(unsigned char *data, unsigned int length,
239                                    unsigned char channel, unsigned char tag,
240                                    unsigned char sy, unsigned int cycle,
241                                    unsigned int dropped)
242         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
243     virtual bool processReadBlock(char *data, unsigned int nevents, unsigned int offset)
244         {debugWarning("call not allowed\n"); return false;};
245
246     // the following methods are to be implemented by transmit SP subclasses
247     virtual enum eChildReturnValue generatePacketHeader(unsigned char *data, unsigned int *length,
248                                       unsigned char *tag, unsigned char *sy,
249                                       int cycle, unsigned int dropped,
250                                       unsigned int max_length)
251         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
252     virtual enum eChildReturnValue generatePacketData(unsigned char *data, unsigned int *length,
253                                     unsigned char *tag, unsigned char *sy,
254                                     int cycle, unsigned int dropped,
255                                     unsigned int max_length)
256         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
257     virtual enum eChildReturnValue generateEmptyPacketHeader(unsigned char *data, unsigned int *length,
258                                             unsigned char *tag, unsigned char *sy,
259                                             int cycle, unsigned int dropped,
260                                             unsigned int max_length)
261         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
262     virtual enum eChildReturnValue generateEmptyPacketData(unsigned char *data, unsigned int *length,
263                                           unsigned char *tag, unsigned char *sy,
264                                           int cycle, unsigned int dropped,
265                                           unsigned int max_length)
266         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
267     virtual enum eChildReturnValue generateSilentPacketHeader(unsigned char *data, unsigned int *length,
268                                             unsigned char *tag, unsigned char *sy,
269                                             int cycle, unsigned int dropped,
270                                             unsigned int max_length)
271         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
272     virtual enum eChildReturnValue generateSilentPacketData(unsigned char *data, unsigned int *length,
273                                           unsigned char *tag, unsigned char *sy,
274                                           int cycle, unsigned int dropped,
275                                           unsigned int max_length)
276         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
277     virtual bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset)
278         {debugWarning("call not allowed\n"); return false;};
279     virtual bool transmitSilenceBlock(char *data, unsigned int nevents, unsigned int offset)
280         {debugWarning("call not allowed\n"); return false;};
281 protected: // some generic helpers
282     int provideSilenceToPort(Port *p, unsigned int offset, unsigned int nevents);
283     bool provideSilenceBlock(unsigned int nevents, unsigned int offset);
284
285 private:
286     bool getFramesDry(unsigned int nbframes, int64_t ts);
287     bool getFramesWet(unsigned int nbframes, int64_t ts);
288     bool putFramesDry(unsigned int nbframes, int64_t ts);
289     bool putFramesWet(unsigned int nbframes, int64_t ts);
290
291     bool transferSilence(unsigned int size);
292
293 public:
294     // move to private?
295     bool xrunOccurred() { return m_in_xrun; };
296
297 // the ISO interface (can we get rid of this?)
298 public:
299     int getChannel() {return m_channel;};
300     bool setChannel(int c)
301         {m_channel = c; return true;};
302
303     virtual unsigned int getNbPacketsIsoXmitBuffer();
304     virtual unsigned int getPacketsPerPeriod();
305     virtual unsigned int getMaxPacketSize() = 0;
306 private:
307     int m_channel;
308
309 protected: // FIXME: move to private
310     uint64_t m_dropped; /// FIXME:debug
311     uint64_t m_last_dropped; /// FIXME:debug
312     int m_last_good_cycle; /// FIXME:debug
313     uint64_t m_last_timestamp; /// last timestamp (in ticks)
314     uint64_t m_last_timestamp2; /// last timestamp (in ticks)
315     bool m_correct_last_timestamp;
316     uint64_t m_last_timestamp_at_period_ticks; // FIXME: still used?
317
318 //--- data buffering and accounting
319 public:
320     void getBufferHeadTimestamp ( ffado_timestamp_t *ts, signed int *fc )
321         {m_data_buffer->getBufferHeadTimestamp(ts, fc);};
322     void getBufferTailTimestamp ( ffado_timestamp_t *ts, signed int *fc )
323         {m_data_buffer->getBufferTailTimestamp(ts, fc);};
324
325     void setBufferTailTimestamp ( ffado_timestamp_t new_timestamp )
326         {m_data_buffer->setBufferTailTimestamp(new_timestamp);};
327     void setBufferHeadTimestamp ( ffado_timestamp_t new_timestamp )
328         {m_data_buffer->setBufferHeadTimestamp(new_timestamp);};
329 protected:
330     Util::TimestampedBuffer *m_data_buffer;
331     // the scratch buffer is temporary buffer space that can be
332     // used by any function. It's pre-allocated when the SP is created.
333     // the purpose is to avoid allocation of memory (or heap/stack) in
334     // an RT context
335     byte_t*         m_scratch_buffer;
336     size_t          m_scratch_buffer_size_bytes;
337
338 protected:
339     // frame counter & sync stuff
340     public:
341         /**
342          * @brief Can this StreamProcessor handle a transfer of nframes frames?
343          *
344          * this function indicates if the streamprocessor can handle a transfer of
345          * nframes frames. It is used to detect underruns-to-be.
346          *
347          * @param nframes number of frames
348          * @return true if the StreamProcessor can handle this amount of frames
349          *         false if it can't
350          */
351         bool canClientTransferFrames(unsigned int nframes);
352
353         /**
354          * \brief return the time until the next period boundary should be signaled (in microseconds)
355          *
356          * Return the time until the next period boundary signal. If this StreamProcessor
357          * is the current synchronization source, this function is called to
358          * determine when a buffer transfer can be made. When this value is
359          * smaller than 0, a period boundary is assumed to be crossed, hence a
360          * transfer can be made.
361          *
362          * \return the time in usecs
363          */
364         int64_t getTimeUntilNextPeriodSignalUsecs();
365         /**
366          * \brief return the time of the next period boundary (in microseconds)
367          *
368          * Returns the time of the next period boundary, in microseconds. The
369          * goal of this function is to determine the exact point of the period
370          * boundary. This is assumed to be the point at which the buffer transfer should
371          * take place, meaning that it can be used as a reference timestamp for transmitting
372          * StreamProcessors
373          *
374          * \return the time in usecs
375          */
376         uint64_t getTimeAtPeriodUsecs();
377
378         /**
379          * \brief return the time of the next period boundary (in internal units)
380          *
381          * The same as getTimeAtPeriodUsecs() but in internal units.
382          *
383          * @return the time in internal units
384          */
385         uint64_t getTimeAtPeriod();
386
387         uint64_t getTimeNow(); // FIXME: should disappear
388
389
390         /**
391          * Returns the sync delay. This is the time a syncsource
392          * delays a period signal, e.g. to cope with buffering.
393          * @return the sync delay
394          */
395         unsigned int getSyncDelay() {return m_sync_delay;};
396         /**
397          * sets the sync delay
398          * @param d sync delay
399          */
400         void setSyncDelay(unsigned int d);
401
402         /**
403          * @brief get the maximal frame latency
404          *
405          * The maximum frame latency is the maximum time that will elapse
406          * between the frame being received by the 1394 stack, and the moment this
407          * frame is presented to the StreamProcessor.
408          *
409          * For transmit SP's this is the maximum time that a frame is requested by
410          * the handler ahead of the time the frame is intended to be transmitted.
411          *
412          * This is useful to figure out how longer than the actual reception time
413          * we have to wait before trying to read the frame from the SP.
414          *
415          * @return maximal frame latency
416          */
417         int getMaxFrameLatency();
418
419         float getTicksPerFrame();
420
421         int getLastCycle() {return m_last_cycle;};
422
423         int getBufferFill();
424
425         // Child implementation interface
426         /**
427         * @brief prepare the child SP
428         * @return true if successful, false otherwise
429         * @pre the m_manager pointer points to a valid manager
430         * @post getEventsPerFrame() returns the correct value
431         * @post getEventSize() returns the correct value
432         * @post getUpdatePeriod() returns the correct value
433         * @post processPacketHeader(...) can be called
434         * @post processPacketData(...) can be called
435         */
436         virtual bool prepareChild() = 0;
437         /**
438          * @brief get the number of events contained in one frame
439          * @return the number of events contained in one frame
440          */
441         virtual unsigned int getEventsPerFrame() = 0;
442
443         /**
444          * @brief get the size of one frame in bytes
445          * @return the size of one frame in bytes
446          */
447         virtual unsigned int getEventSize() = 0;
448
449         /**
450          * @brief get the nominal number of frames in a packet
451          *
452          * This is the amount of frames that is nominally present
453          * in one packet. It is recommended that in the receive handler
454          * you write this amount of frames when a valid packet has
455          * been received. (although this is not mandatory)
456          *
457          * @return the nominal number of frames in a packet
458          */
459         virtual unsigned int getNominalFramesPerPacket() = 0;
460
461         /**
462          * @brief get the nominal number of packets needed for a certain amount of frames
463          * @return the nominal number of packet necessary
464          */
465         virtual unsigned int getNominalPacketsNeeded(unsigned int nframes);
466
467         /**
468          * @brief returns the actual frame rate as calculated by the SP's DLL
469          * @return the actual frame rate as detected by the DLL
470          */
471         float getActualRate()
472             {return m_data_buffer->getRate();};
473
474     protected:
475         float m_ticks_per_frame;
476         int m_last_cycle;
477         unsigned int m_sync_delay;
478     private:
479         bool m_in_xrun;
480         pthread_mutex_t m_activity_cond_lock;
481         pthread_cond_t  m_activity_cond;
482
483 public:
484     // debug stuff
485     virtual void dumpInfo();
486     virtual void setVerboseLevel(int l);
487     const char *getStateString()
488         {return ePSToString(getState());};
489     const char *getTypeString()
490         {return ePTToString(getType());};
491     StreamStatistics m_PacketStat;
492     StreamStatistics m_PeriodStat;
493     StreamStatistics m_WakeupStat;
494     DECLARE_DEBUG_MODULE;
495 };
496
497 }
498
499 #endif /* __FFADO_STREAMPROCESSOR__ */
500
501
Note: See TracBrowser for help on using the browser.