root/branches/ppalmers-streaming/src/libstreaming/generic/StreamProcessor.cpp

Revision 715, 11.3 kB (checked in by ppalmers, 15 years ago)

some more cleaning

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 library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License version 2.1, as published by the Free Software Foundation;
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301 USA
22  */
23
24 #include "StreamProcessor.h"
25 #include "../util/cycletimer.h"
26 #include "../StreamProcessorManager.h"
27
28 #include "libutil/Atomic.h"
29
30 #include <assert.h>
31 #include <math.h>
32
33 namespace Streaming {
34
35 IMPL_DEBUG_MODULE( StreamProcessor, StreamProcessor, DEBUG_LEVEL_VERBOSE );
36
37 StreamProcessor::StreamProcessor(enum eProcessorType type, int port)
38     : IsoStream((type==ePT_Receive ? IsoStream::eST_Receive : IsoStream::eST_Transmit), port)
39     , m_processor_type ( type )
40     , m_state( ePS_Created )
41     , m_xruns( 0 )
42     , m_manager(NULL)
43     , m_running(false)
44     , m_disabled(true)
45     , m_is_disabled(true)
46     , m_cycle_to_enable_at(0)
47     , m_ticks_per_frame(0)
48     , m_last_cycle(0)
49     , m_sync_delay(0)
50 {
51     // create the timestamped buffer and register ourselves as its client
52     m_data_buffer=new Util::TimestampedBuffer(this);
53
54 }
55
56 StreamProcessor::~StreamProcessor() {
57     if (m_data_buffer) delete m_data_buffer;
58 }
59
60 void
61 StreamProcessor::setState(enum eProcessorState s) {
62     #ifdef DEBUG
63         // check the state transistion
64         debugOutput( DEBUG_LEVEL_VERBOSE, "State transition from %s to %s",
65             ePSToString(m_state), ePSToString(s) );
66     #endif
67     m_state = s;
68 }
69
70 void StreamProcessor::dumpInfo()
71 {
72     debugOutputShort( DEBUG_LEVEL_NORMAL, " StreamProcessor information\n");
73     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Iso stream info:\n");
74
75     IsoStream::dumpInfo();
76     debugOutputShort( DEBUG_LEVEL_NORMAL, "  StreamProcessor info:\n");
77     if (m_handler)
78         debugOutputShort( DEBUG_LEVEL_NORMAL, "  Now                   : %011u\n",m_handler->getCycleTimerTicks());
79     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Xruns                 : %d\n", m_xruns);
80     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Running               : %d\n", m_running);
81     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Enabled               : %s\n", m_disabled ? "No" : "Yes");
82     debugOutputShort( DEBUG_LEVEL_NORMAL, "   enable status        : %s\n", m_is_disabled ? "No" : "Yes");
83
84     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Nominal framerate     : %u\n", m_manager->getNominalRate());
85     debugOutputShort( DEBUG_LEVEL_NORMAL, "  Device framerate      : Sync: %f, Buffer %f\n",
86         24576000.0/getSyncSource().m_data_buffer->getRate(),
87         24576000.0/m_data_buffer->getRate()
88         );
89
90     m_data_buffer->dumpInfo();
91
92     m_PeriodStat.dumpInfo();
93     m_PacketStat.dumpInfo();
94 //     m_WakeupStat.dumpInfo();
95 }
96
97 bool StreamProcessor::init()
98 {
99     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "enter...\n");
100     m_data_buffer->init();
101     return IsoStream::init();
102 }
103
104 /**
105  * Resets the frame counter, the xrun counter, the ports and the iso stream.
106  * @return true if reset succeeded
107  */
108 bool StreamProcessor::reset() {
109
110     debugOutput( DEBUG_LEVEL_VERBOSE, "Resetting...\n");
111
112     // reset the event buffer, discard all content
113     if (!m_data_buffer->reset()) {
114         debugFatal("Could not reset data buffer\n");
115         return false;
116     }
117
118     resetXrunCounter();
119
120     // loop over the ports to reset them
121     if (!PortManager::resetPorts()) {
122         debugFatal("Could not reset ports\n");
123         return false;
124     }
125
126     // reset the iso stream
127     if (!IsoStream::reset()) {
128         debugFatal("Could not reset isostream\n");
129         return false;
130     }
131     return true;
132
133 }
134
135 bool StreamProcessor::prepareForEnable(uint64_t time_to_enable_at) {
136     debugOutput(DEBUG_LEVEL_VERBOSE," StreamProcessor::prepareForEnable for (%p)\n",this);
137     debugOutput(DEBUG_LEVEL_VERBOSE,"  Now                   : %011u\n",m_handler->getCycleTimerTicks());
138     debugOutput(DEBUG_LEVEL_VERBOSE,"  Enable at             : %011u\n",time_to_enable_at);
139     m_data_buffer->dumpInfo();
140     return true;
141 }
142
143 bool StreamProcessor::prepareForDisable() {
144     debugOutput(DEBUG_LEVEL_VERBOSE," StreamProcessor::prepareForDisable for (%p)\n",this);
145     debugOutput(DEBUG_LEVEL_VERBOSE,"  Now                   : %011u\n",m_handler->getCycleTimerTicks());
146     m_data_buffer->dumpInfo();
147     return true;
148 }
149
150 bool StreamProcessor::prepare() {
151
152     debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing...\n");
153     if(!m_manager) {
154         debugFatal("Not attached to a manager!\n");
155         return -1;
156     }
157
158     // init the ports
159     // loop over the ports to reset them
160     PortManager::preparePorts();
161
162     // reset the iso stream
163     IsoStream::prepare();
164
165     return true;
166
167 }
168
169 StreamProcessor&
170 StreamProcessor::getSyncSource()
171 {
172     return m_manager->getSyncSource();
173 };
174
175 int StreamProcessor::getBufferFill() {
176 //     return m_data_buffer->getFrameCounter();
177     return m_data_buffer->getBufferFill();
178 }
179
180 uint64_t StreamProcessor::getTimeNow() {
181     return m_handler->getCycleTimerTicks();
182 }
183
184
185 int StreamProcessor::getMaxFrameLatency() {
186     if (getType() == ePT_Receive) {
187         return (int)(m_handler->getWakeupInterval() * TICKS_PER_CYCLE);
188     } else {
189         return (int)(m_handler->getWakeupInterval() * TICKS_PER_CYCLE);
190     }
191 }
192
193 bool StreamProcessor::isRunning() {
194     return m_running;
195 }
196
197 bool StreamProcessor::enable(uint64_t time_to_enable_at)  {
198     // FIXME: time_to_enable_at will be in 'time' not cycles
199     m_cycle_to_enable_at=time_to_enable_at;
200
201     if(!m_running) {
202             debugWarning("The StreamProcessor is not running yet, enable() might not be a good idea.\n");
203     }
204
205 #ifdef DEBUG
206     uint64_t now_cycles=CYCLE_TIMER_GET_CYCLES(m_handler->getCycleTimer());
207     const int64_t max=(int64_t)(CYCLES_PER_SECOND/2);
208
209     int64_t diff=(int64_t)m_cycle_to_enable_at-(int64_t)now_cycles;
210
211     if (diff > max) {
212         diff-=TICKS_PER_SECOND;
213     } else if (diff < -max) {
214         diff+=TICKS_PER_SECOND;
215     }
216
217     if (diff<0) {
218         debugWarning("Request to enable streamprocessor %lld cycles ago (now=%llu, cy=%llu).\n",
219             diff,now_cycles,time_to_enable_at);
220     }
221 #endif
222     m_data_buffer->enable();
223
224     m_disabled=false;
225     return true;
226 }
227
228 bool StreamProcessor::disable()  {
229     m_data_buffer->disable();
230     m_disabled=true;
231     return true;
232 }
233
234 float
235 StreamProcessor::getTicksPerFrame() {
236     if (m_data_buffer) {
237         float rate=m_data_buffer->getRate();
238         if (fabsf(m_ticks_per_frame - rate)>(m_ticks_per_frame*0.1)) {
239             debugWarning("TimestampedBuffer rate (%10.5f) more that 10%% off nominal (%10.5f)\n",rate,m_ticks_per_frame);
240             return m_ticks_per_frame;
241         }
242 //         return m_ticks_per_frame;
243         if (rate<0.0) debugError("rate < 0! (%f)\n",rate);
244        
245         return rate;
246     } else {
247         return 0.0;
248     }
249 }
250
251 int64_t StreamProcessor::getTimeUntilNextPeriodSignalUsecs() {
252     uint64_t time_at_period=getTimeAtPeriod();
253
254     // we delay the period signal with the sync delay
255     // this makes that the period signals lag a little compared to reality
256     // ISO buffering causes the packets to be received at max
257     // m_handler->getWakeupInterval() later than the time they were received.
258     // hence their payload is available this amount of time later. However, the
259     // period boundary is predicted based upon earlier samples, and therefore can
260     // pass before these packets are processed. Adding this extra term makes that
261     // the period boundary is signalled later
262     time_at_period = addTicks(time_at_period, getSyncSource().getSyncDelay());
263
264     uint64_t cycle_timer=m_handler->getCycleTimerTicks();
265
266     // calculate the time until the next period
267     int32_t until_next=diffTicks(time_at_period,cycle_timer);
268
269     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> TAP=%11llu, CTR=%11llu, UTN=%11ld\n",
270         time_at_period, cycle_timer, until_next
271         );
272
273     // now convert to usecs
274     // don't use the mapping function because it only works
275     // for absolute times, not the relative time we are
276     // using here (which can also be negative).
277     return (int64_t)(((float)until_next) / TICKS_PER_USEC);
278 }
279
280 uint64_t StreamProcessor::getTimeAtPeriodUsecs() {
281     return (uint64_t)((float)getTimeAtPeriod() * TICKS_PER_USEC);
282 }
283
284 bool StreamProcessor::dropFrames(unsigned int nbframes) {
285     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "StreamProcessor::dropFrames(%d)\n", nbframes);
286     return m_data_buffer->dropFrames(nbframes);
287 }
288
289 /**
290  * Resets the xrun counter, in a atomic way. This
291  * is thread safe.
292  */
293 void StreamProcessor::resetXrunCounter() {
294     ZERO_ATOMIC((SInt32 *)&m_xruns);
295 }
296
297 void StreamProcessor::setVerboseLevel(int l) {
298     setDebugLevel(l);
299     IsoStream::setVerboseLevel(l);
300     PortManager::setVerboseLevel(l);
301     m_data_buffer->setVerboseLevel(l);
302 }
303
304 uint64_t
305 StreamProcessor::getTimeAtPeriod() {
306     if (getType() == ePT_Receive) {
307         ffado_timestamp_t next_period_boundary=m_data_buffer->getTimestampFromHead(m_manager->getPeriodSize());
308    
309         #ifdef DEBUG
310         ffado_timestamp_t ts;
311         signed int fc;
312         m_data_buffer->getBufferTailTimestamp(&ts,&fc);
313    
314         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> NPD="TIMESTAMP_FORMAT_SPEC", LTS="TIMESTAMP_FORMAT_SPEC", FC=%5u, TPF=%f\n",
315             next_period_boundary, ts, fc, getTicksPerFrame()
316             );
317         #endif
318         return (uint64_t)next_period_boundary;
319     } else {
320         ffado_timestamp_t next_period_boundary=m_data_buffer->getTimestampFromTail((m_manager->getNbBuffers()-1) * m_manager->getPeriodSize());
321    
322         #ifdef DEBUG
323         ffado_timestamp_t ts;
324         signed int fc;
325         m_data_buffer->getBufferTailTimestamp(&ts,&fc);
326    
327         debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "=> NPD="TIMESTAMP_FORMAT_SPEC", LTS="TIMESTAMP_FORMAT_SPEC", FC=%5u, TPF=%f\n",
328             next_period_boundary, ts, fc, getTicksPerFrame()
329             );
330         #endif
331         return (uint64_t)next_period_boundary;
332     }
333 }
334
335 bool
336 StreamProcessor::canClientTransferFrames(unsigned int nbframes) {
337     if (getType() == ePT_Receive) {
338         return m_data_buffer->getFrameCounter() >= (int) nbframes;
339     } else {
340         bool can_transfer;
341         // there has to be enough space to put the frames in
342         can_transfer = m_data_buffer->getBufferSize() - m_data_buffer->getFrameCounter() > nbframes;
343         // or the buffer is transparent
344         can_transfer |= m_data_buffer->isTransparent();
345         return can_transfer;
346     }
347 }
348
349 const char *
350 StreamProcessor::ePSToString(enum eProcessorState s) {
351     switch (s) {
352         case ePS_Created: return "ePS_Created";
353         case ePS_Initialized: return "ePS_Initialized";
354         case ePS_WaitingForRunningStream: return "ePS_WaitingForRunningStream";
355         case ePS_DryRunning: return "ePS_DryRunning";
356         case ePS_WaitingForEnabledStream: return "ePS_WaitingForEnabledStream";
357         case ePS_StreamEnabled: return "ePS_StreamEnabled";
358         case ePS_WaitingForDisabledStream: return "ePS_WaitingForDisabledStream";
359     }
360 }
361
362 } // end of namespace
Note: See TracBrowser for help on using the browser.