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

Revision 750, 17.3 kB (checked in by ppalmers, 13 years ago)

Code refactoring. Tries to simplify things and tries to put all code where it belongs.

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