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

Revision 709, 10.6 kB (checked in by ppalmers, 15 years ago)

some more streaming system updates.
this works with the saffire up till -n2 -p256

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