root/branches/libffado-2.0/src/libstreaming/generic/StreamProcessor.h

Revision 1525, 17.5 kB (checked in by ppalmers, 12 years ago)

- Allow to specify the DLL bandwidths for the CycleTimerHelper? and the TimestampedBuffer? in absolute units (Hz). This ensures samplerate-independent operation
- Reduce the default DLL bandwidth for the TimestampedBuffer?'s. This improves timestamp timing with a factor 10x, which should benefit especially the timing sensitive devices (MOTU).
- Allow to specify the DLL bandwith and other transmit settings through the configuration file
- Implement a sanity check for the instantanous samplerate to detect bogus timestamp processing

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/TimestampedBuffer.h"
32 #include "libutil/OptionContainer.h"
33
34 #include "debugmodule/debugmodule.h"
35
36 #include <pthread.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_Stopped,
75         ePS_WaitingForStream,
76         ePS_DryRunning,
77         ePS_WaitingForStreamEnable,
78         ePS_Running,
79         ePS_WaitingForStreamDisable,
80         ePS_Error,
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     bool inError()
116             {return m_state == ePS_Error;};
117
118     // these schedule and wait for the state transition
119     bool startDryRunning(int64_t time_to_start_at);
120     bool startRunning(int64_t time_to_start_at);
121     bool stopDryRunning(int64_t time_to_stop_at);
122     bool stopRunning(int64_t time_to_stop_at);
123
124     // these only schedule the transition
125     bool scheduleStartDryRunning(int64_t time_to_start_at);
126     bool scheduleStartRunning(int64_t time_to_start_at);
127     bool scheduleStopDryRunning(int64_t time_to_stop_at);
128     bool scheduleStopRunning(int64_t time_to_stop_at);
129
130     // the main difference between init and prepare is that when prepare is called,
131     // the SP is registered to a manager (FIXME: can't it be called by the manager?)
132     bool init();
133     bool prepare();
134
135     bool handleBusReset();
136
137     // the one to be implemented by the child class
138     virtual bool handleBusResetDo();
139
140     FFADODevice& getParent() {return m_Parent;};
141
142 public: // constructor/destructor
143     StreamProcessor(FFADODevice &parent, enum eProcessorType type);
144     virtual ~StreamProcessor();
145 protected:
146     FFADODevice&                m_Parent;
147     Ieee1394Service&            m_1394service;
148     IsoHandlerManager&          m_IsoHandlerManager;
149     StreamProcessorManager&     m_StreamProcessorManager;
150     unsigned int                m_local_node_id;
151
152 public: // the public receive/transmit functions
153     // the transmit interface accepts frames and provides packets
154     // implement these for a transmit SP
155     // leave default for a receive SP
156
157     // the receive interface accepts packets and provides frames
158     // these are implemented by the parent SP
159     enum raw1394_iso_disposition
160         putPacket(unsigned char *data, unsigned int length,
161                   unsigned char channel, unsigned char tag, unsigned char sy,
162                   uint32_t pkt_ctr, unsigned int dropped);
163
164     enum raw1394_iso_disposition
165     getPacket(unsigned char *data, unsigned int *length,
166               unsigned char *tag, unsigned char *sy,
167               uint32_t pkt_ctr, unsigned int dropped,
168               unsigned int skipped, unsigned int max_length);
169
170     bool getFrames(unsigned int nbframes, int64_t ts); ///< transfer the buffer contents to the client
171     bool putFrames(unsigned int nbframes, int64_t ts); ///< transfer the client contents to the buffer
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 tag, unsigned char sy,
235                                                        uint32_t pkt_ctr)
236         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
237     virtual enum eChildReturnValue processPacketData(unsigned char *data, unsigned int length)
238         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
239     virtual bool processReadBlock(char *data, unsigned int nevents, unsigned int offset)
240         {debugWarning("call not allowed\n"); return false;};
241
242     // the following methods are to be implemented by transmit SP subclasses
243     virtual enum eChildReturnValue generatePacketHeader(unsigned char *data, unsigned int *length,
244                                                         unsigned char *tag, unsigned char *sy,
245                                                         uint32_t pkt_ctr)
246         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
247     virtual enum eChildReturnValue generatePacketData(unsigned char *data, unsigned int *length)
248         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
249     virtual enum eChildReturnValue generateEmptyPacketHeader(unsigned char *data, unsigned int *length,
250                                                              unsigned char *tag, unsigned char *sy,
251                                                              uint32_t pkt_ctr)
252         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
253     virtual enum eChildReturnValue generateEmptyPacketData(unsigned char *data, unsigned int *length)
254         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
255     virtual enum eChildReturnValue generateSilentPacketHeader(unsigned char *data, unsigned int *length,
256                                                               unsigned char *tag, unsigned char *sy,
257                                                               uint32_t pkt_ctr)
258         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
259     virtual enum eChildReturnValue generateSilentPacketData(unsigned char *data, unsigned int *length)
260         {debugWarning("call not allowed\n"); return eCRV_Invalid;};
261     virtual bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset)
262         {debugWarning("call not allowed\n"); return false;};
263     virtual bool transmitSilenceBlock(char *data, unsigned int nevents, unsigned int offset)
264         {debugWarning("call not allowed\n"); return false;};
265 protected: // some generic helpers
266     int provideSilenceToPort(Port *p, unsigned int offset, unsigned int nevents);
267     bool provideSilenceBlock(unsigned int nevents, unsigned int offset);
268
269 private:
270     bool getFramesDry(unsigned int nbframes, int64_t ts);
271     bool getFramesWet(unsigned int nbframes, int64_t ts);
272     bool putFramesDry(unsigned int nbframes, int64_t ts);
273     bool putFramesWet(unsigned int nbframes, int64_t ts);
274
275     bool transferSilence(unsigned int size);
276
277 public:
278     // move to private?
279     bool xrunOccurred() { return m_in_xrun; };
280     void handlerDied();
281
282 // the ISO interface (can we get rid of this?)
283 public:
284     int getChannel() {return m_channel;};
285     bool setChannel(int c)
286         {m_channel = c; return true;};
287
288     virtual unsigned int getNbPacketsIsoXmitBuffer();
289     virtual unsigned int getPacketsPerPeriod();
290     virtual unsigned int getMaxPacketSize() = 0;
291 private:
292     int m_channel;
293
294 protected: // FIXME: move to private
295     uint64_t m_last_timestamp; /// last timestamp (in ticks)
296 private:
297     uint64_t m_last_timestamp2; /// last timestamp (in ticks)
298 protected:
299     bool m_correct_last_timestamp;
300     uint64_t m_last_timestamp_at_period_ticks; // FIXME: still used?
301
302 //--- data buffering and accounting
303 public:
304     void getBufferHeadTimestamp ( ffado_timestamp_t *ts, signed int *fc )
305         {m_data_buffer->getBufferHeadTimestamp(ts, fc);};
306     void getBufferTailTimestamp ( ffado_timestamp_t *ts, signed int *fc )
307         {m_data_buffer->getBufferTailTimestamp(ts, fc);};
308
309     void setBufferTailTimestamp ( ffado_timestamp_t new_timestamp )
310         {m_data_buffer->setBufferTailTimestamp(new_timestamp);};
311     void setBufferHeadTimestamp ( ffado_timestamp_t new_timestamp )
312         {m_data_buffer->setBufferHeadTimestamp(new_timestamp);};
313 protected:
314     Util::TimestampedBuffer *m_data_buffer;
315     // the scratch buffer is temporary buffer space that can be
316     // used by any function. It's pre-allocated when the SP is created.
317     // the purpose is to avoid allocation of memory (or heap/stack) in
318     // an RT context
319     byte_t*         m_scratch_buffer;
320     size_t          m_scratch_buffer_size_bytes;
321
322 protected:
323     // frame counter & sync stuff
324     public:
325         /**
326          * @brief Can this StreamProcessor handle a transfer of nframes frames?
327          *
328          * this function indicates if the streamprocessor can handle a transfer of
329          * nframes frames. It is used to detect underruns-to-be.
330          *
331          * @param nframes number of frames
332          * @return true if the StreamProcessor can handle this amount of frames
333          *         false if it can't
334          */
335         bool canClientTransferFrames(unsigned int nframes);
336
337         /**
338          * \brief return the time until the next period boundary should be signaled (in microseconds)
339          *
340          * Return the time until the next period boundary signal. If this StreamProcessor
341          * is the current synchronization source, this function is called to
342          * determine when a buffer transfer can be made. When this value is
343          * smaller than 0, a period boundary is assumed to be crossed, hence a
344          * transfer can be made.
345          *
346          * \return the time in usecs
347          */
348         int64_t getTimeUntilNextPeriodSignalUsecs();
349         /**
350          * \brief return the time of the next period boundary (in microseconds)
351          *
352          * Returns the time of the next period boundary, in microseconds. The
353          * goal of this function is to determine the exact point of the period
354          * boundary. This is assumed to be the point at which the buffer transfer should
355          * take place, meaning that it can be used as a reference timestamp for transmitting
356          * StreamProcessors
357          *
358          * \return the time in usecs
359          */
360         uint64_t getTimeAtPeriodUsecs();
361
362         /**
363          * \brief return the time of the next period boundary (in internal units)
364          *
365          * The same as getTimeAtPeriodUsecs() but in internal units.
366          *
367          * @return the time in internal units
368          */
369         uint64_t getTimeAtPeriod();
370
371         uint64_t getTimeNow(); // FIXME: should disappear
372
373
374         /**
375          * Returns the sync delay. This is the time a syncsource
376          * delays a period signal, e.g. to cope with buffering.
377          * @return the sync delay (in ticks)
378          */
379         unsigned int getSyncDelay() {return m_sync_delay;};
380         unsigned int getSyncDelayFrames();
381         /**
382          * sets the sync delay
383          * @param d sync delay
384          */
385         void setSyncDelay(unsigned int d);
386
387         /**
388          * @brief get the maximal frame latency
389          *
390          * The maximum frame latency is the maximum time that will elapse
391          * between the frame being received by the 1394 stack, and the moment this
392          * frame is presented to the StreamProcessor.
393          *
394          * For transmit SP's this is the maximum time that a frame is requested by
395          * the handler ahead of the time the frame is intended to be transmitted.
396          *
397          * This is useful to figure out how longer than the actual reception time
398          * we have to wait before trying to read the frame from the SP.
399          *
400          * @return maximal frame latency
401          */
402         int getMaxFrameLatency();
403
404         float getTicksPerFrame();
405         void setTicksPerFrame(float tpf);
406
407         bool setDllBandwidth(float bw);
408
409         int getBufferFill();
410
411         // Child implementation interface
412         /**
413         * @brief prepare the child SP
414         * @return true if successful, false otherwise
415         * @pre the m_manager pointer points to a valid manager
416         * @post getEventsPerFrame() returns the correct value
417         * @post getEventSize() returns the correct value
418         * @post getUpdatePeriod() returns the correct value
419         * @post processPacketHeader(...) can be called
420         * @post processPacketData(...) can be called
421         */
422         virtual bool prepareChild() = 0;
423         /**
424          * @brief get the number of events contained in one frame
425          * @return the number of events contained in one frame
426          */
427         virtual unsigned int getEventsPerFrame() = 0;
428
429         /**
430          * @brief get the size of one frame in bytes
431          * @return the size of one frame in bytes
432          */
433         virtual unsigned int getEventSize() = 0;
434
435         /**
436          * @brief get the nominal number of frames in a packet
437          *
438          * This is the amount of frames that is nominally present
439          * in one packet. It is recommended that in the receive handler
440          * you write this amount of frames when a valid packet has
441          * been received. (although this is not mandatory)
442          *
443          * @return the nominal number of frames in a packet
444          */
445         virtual unsigned int getNominalFramesPerPacket() = 0;
446
447         /**
448          * @brief get the nominal number of packets needed for a certain amount of frames
449          * @return the nominal number of packet necessary
450          */
451         virtual unsigned int getNominalPacketsNeeded(unsigned int nframes);
452
453     protected:
454         float m_ticks_per_frame;
455         float m_dll_bandwidth_hz;
456         unsigned int m_sync_delay;
457     private:
458         bool m_in_xrun;
459
460 public:
461     // debug stuff
462     virtual void dumpInfo();
463     virtual void printBufferInfo();
464     virtual void setVerboseLevel(int l);
465     const char *getStateString()
466         {return ePSToString(getState());};
467     const char *getTypeString()
468         {return ePTToString(getType());};
469
470     DECLARE_DEBUG_MODULE;
471 };
472
473 }
474
475 #endif /* __FFADO_STREAMPROCESSOR__ */
476
477
Note: See TracBrowser for help on using the browser.