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

Revision 967, 19.0 kB (checked in by ppalmers, 16 years ago)

- first attempt at not causing total havoc when devices are removed from the bus.

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