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

Revision 714, 11.6 kB (checked in by ppalmers, 15 years ago)

- cleanup of streaming interfaces
- doesn't work yet

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