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

Revision 833, 19.1 kB (checked in by ppalmers, 14 years ago)

merge api-cleanup branch (R808:832) into trunk

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